Как Bloomberg блокирует парсинг. Как определяет бота?

Вообщем нужны котировки блумберга. Я делаю вот такой запрос в браузере для получения котировки например по тайскому бату. Урл я нашел анализирую страницу валюты.

https://www.bloomberg.com/markets2/api/history/THB:CUR/PX_LAST?timeframe=1_YEAR&period=daily&volumePeriod=daily

Через браузер работает все исправно, еще и без прокси. Я вижу через консоль, что запрос по протоколу h2. Пытаюсь повторить, беру python 2.7 requests - не получается, возвращает редирект на страницу. Причем беру все заголовки из вкладки сеть браузера, user-agent тоже.

https://www.bloomberg.com/tosv2.html?vid=&uuid=e6018a57-e20a-11ef-90bb-f3cb1c447cb1&url=L21hcmtldHMyL2FwaS9oaXN0b3J5L1VTRERaRDpDVVIvUFhfTEFTVD90aW1lZnJhbWU9MV9ZRUFSJnBlcmlvZD1kYWlseSZ2b2x1bWVQZXJpb2Q9ZGFpbHk=

Где собственно информация, что возможно вы бот)

Ладно беру php curl 7.4 - также не получается, бот... Беру php 8.3 Как я понял там есть поддержка h2, делаю запрос и о чудо он работает! Не всегда, но через раз определяет что бот. Если через прокси работаю, то примерно 60-70% успешных запросов...

Ладно, пробую брать последнюю версию консольного curl с поддержкой h2 - и... не работает. постоянно определяет что бот, да как так то? Прошу помощи объяснить подсказать как bloomberg определяет бота? И как можно обойти это ограничение.

Пример запроса на curl (прокси уберу):

curl --user-agent "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4103.106 Safari/537.36" -H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7" -H "Accept-Encoding: gzip, deflate, br" -H "Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7" -H "Cache-Control: no-cache" -H "Cookie: exp_pref=EUR; country_code=RU;" -H "Dnt: 1" -H "Pragma: no-cache" -H "Sec-Ch-Ua: "Chromium";v="5", "Not/A)Brand";v="24"" -H "Sec-Ch-Ua-Mobile: ?0" -H "Sec-Ch-Ua-Platform: "Windows"" -H "Sec-Fetch-Dest: document" -H "Sec-Fetch-Mode: navigate" -H "Sec-Fetch-Site: none" -H "Sec-Fetch-User: ?1" -H "Upgrade-Insecure-Requests: 1" "https://www.bloomberg.com/markets2/api/history/USDDZD:CUR/PX_LAST?timeframe=1_YEAR&period=daily&volumePeriod=daily" -v

ключ -v я добавил, чтобы видеть все заголовки, есть небольшая разница между запросом php и curl в сертификатах, которые они используют, может ли дело быть в них?


Ответы (1 шт):

Автор решения: Pak Uula

Вы попробовали для начала открыть веб-сайт блумберга? Когда я туда зашел браузером, он меня порадовал сообщением, что с моего адреса идёт подозрительная активность, и предложил капчу. После этого запросы curl заработали:

curl 'https://www.bloomberg.com/markets2/api/history/THB:CUR/PX_LAST?timeframe=1_YEAR&period=daily&volumePeriod=daily' \
  -H 'DNT: 1' \
  -H 'Upgrade-Insecure-Requests: 1' \
  -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36' \
  -H 'sec-ch-ua: "Not A(Brand";v="8", "Chromium";v="132", "Google Chrome";v="132"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "Windows"'

(строка запроса скопирована из Chrome Dev Tools / Network)

То же самое в Python-3.13

import requests

# curl 'https://www.bloomberg.com/markets2/api/history/THB:CUR/PX_LAST?timeframe=1_YEAR&period=daily&volumePeriod=daily' \
#   -H 'DNT: 1' \
#   -H 'Upgrade-Insecure-Requests: 1' \
#   -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36' \
#   -H 'sec-ch-ua: "Not A(Brand";v="8", "Chromium";v="132", "Google Chrome";v="132"' \
#   -H 'sec-ch-ua-mobile: ?0' \
#   -H 'sec-ch-ua-platform: "Windows"'
headers = {
    'DNT': '1',
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36',
    'sec-ch-ua': '"Not A(Brand";v="8", "Chromium";v="132", "Google Chrome";v="132"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Windows"'
}

def get(url):
    response = requests.get(url, headers=headers)
    return response.text

if __name__ == "__main__":
    url = 'https://www.bloomberg.com/markets2/api/history/THB:CUR/PX_LAST?timeframe=1_YEAR&period=daily&volumePeriod=daily'
    json_str = get(url)
    json_rsp = json.loads(json_str)
    match json_rsp:
        case list():
            for obj in json_rsp:
                if 'price' in obj:
                    for day in obj['price']:
                        print(f"{day['dateTime']}: {day['value']:.03f}")
        case _:
            print("Что-то странное. Ожидался список, получено:", type(json_rsp))
            print(json_rsp)

Вывод

2024-02-05: 35.805
2024-02-06: 35.577
2024-02-07: 35.615
2024-02-08: 35.857
...
2025-01-31: 33.731
2025-02-03: 34.075
→ Ссылка