Большинство скраперов терпят неудачу еще до того, как будет прочитан хотя бы один заголовок.
Сервер смотрит на сигнатуру соединения, которую ваш клиент отправляет в сеть, и решает, браузер ли вы или клиентская библиотека, притворяющаяся им. Python requests, net/http в Go, обычный curl: все они передают характерный отпечаток в момент приветствия. Сайты, которым это важно (Datadome, Akamai, Imperva, управляемая сторона Cloudflare), разрывают соединение или показывают страницу проверки до того, как ваша строка User-Agent начнет иметь значение.
Именно эту проблему решает unblocker: true в FourA. В прошлом месяце мы определили компоненты, которые обеспечивают его надежную работу.
Что нового
unblocker: true - это единственный флаг в любом вызове /api/single. Включите его, и мы сделаем три вещи: внедрим набор заголовков браузера, отправим запрос через транспорт, который соответствует тому, что реальный браузер передает в сеть, и распакуем то, что возвращает сервер (gzip, brotli, deflate). Первые два были доступны со времен беты. Третий (автоматическая распаковка brotli) был выпущен 25 марта, а работа по привязке версий была завершена на следующий день, чтобы синхронизировать заголовки и транспорт.
Как это работает
Вот как выглядит запрос:
curl -X POST "https://api.foura.ai/api/single" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"url": "https://example.com/products",
"method": "GET",
"unblocker": true
}'
Под капотом работают три уровня.
Внедрение заголовков. Мы устанавливаем полный набор заголовков браузера: User-Agent, Sec-Ch-Ua, Sec-Ch-Ua-Platform, Sec-Fetch-Site, Sec-Fetch-Mode, Sec-Fetch-Dest, Accept, Accept-Language и Accept-Encoding. Порядок имеет значение. Реальные браузеры генерируют их в определенной последовательности, и библиотеки обнаружения проверяют это.
Сигнатура соединения. Наш транспорт соответствует структуре на уровне байтов актуальной сессии браузера: тот же порядок расширений, те же предпочтения шифров, те же особенности рукопожатия. Стандартный curl, Python requests и net/http в Go создают сигнатуры, которые автоматически блокируются за миллисекунды на защищенной инфраструктуре.
Автоматическая распаковка. Когда unblocker включен, мы устанавливаем Accept-Encoding на gzip, deflate, br, и транспорт распаковывает тело. Вы получаете декодированную строку (или Buffer, если вы передаете returnBuffer: true). Никакой ручной обработки brotli, никаких несовпадений между заголовками и телом, когда сайт выбирает deflate вместо gzip.
Почему важна привязка версий
Сигнатуры соединений привязаны к версиям. Детали сетевого уровня браузера в этом месяце не совпадают с деталями прошлого месяца, и сайт, который тщательно снимает отпечатки, заметит это отклонение. Мы связываем движущиеся части вместе, чтобы заголовки, объекты навигатора и сигнатура соединения сообщали об одной и той же версии браузера.
Если это звучит сложно, так оно и есть. Мы столкнулись с несовпадением во время миграции монорепозитория в марте, когда один компонент автоматически обновился, а остальные рассинхронизировались. Исправление заняло два коммита: зафиксировать движущуюся часть и никогда не доверять менеджеру пакетов в поддержании синхронизации.
Влияние
Во внутренних тестах на целях с жесткой проверкой отпечатков (финансы, путешествия, защищенная электронная коммерция) разница между unblocker: false и unblocker: true - это разница между страницей проверки и 200. Обычный curl, обращающийся к управляемому Cloudflare, сразу получает 403. Тот же URL с unblocker: true проходит, потому что на сетевом уровне соединение выглядит как сессия браузера.
Но для сайтов, которые не снимают отпечатки (большинство публичных API, старые шаблоны CMS, все, что ограничено только лимитами частоты по IP), отключение unblocker вполне допустимо и экономит несколько миллисекунд согласования. Используйте это там, где это необходимо.
Для продвинутых пользователей
Несколько шаблонов, о которых стоит знать.
Совмещайте unblocker с резидентными прокси, когда цель также проверяет репутацию IP. IP датацентров плюс идеальная сигнатура соединения все равно блокируются на ASN, которые сайт занес в черный список. Наш эндпоинт прокси (/api/proxy) ротируется по целевому домену, поэтому добавления "proxy": "residential" к запросу обычно достаточно.
Пропускайте unblocker при вызове JSON API, которым не важны браузеры. Дополнительные заголовки могут выглядеть подозрительно для API, который ожидает программного клиента, например, бэкенд, вызывающий собственный микросервис.
Если на сайте работает защита от ботов на JavaScript (интерактивные проверки Turnstile, PerimeterX в самом строгом режиме, Akamai Bot Manager с усиленной эвристикой), одного unblocker будет недостаточно. Вам нужен эндпоинт браузера, который выполняет проверку в полноценном браузере. Это другой продукт с другой стоимостью кредитов, и мы писали о нем в Browser Tasks: How to Scrape JavaScript-Heavy Sites.
И вы можете комбинировать unblocker с блоком validate, чтобы отклонять ответы, которые технически возвращают 200, но содержат страницу проверки:
{
"url": "https://example.com/products",
"method": "GET",
"unblocker": true,
"validate": {
"data": { "fail": ["captcha", "Access Denied"] }
}
}
Это превращает скрытые ошибки в классифицированные ошибки, что важно для отслеживания процента успешных запросов в панели управления.
Что дальше
Браузеры выпускают новую стабильную версию каждые четыре недели. Мы обновляем наш стек, чтобы соответствовать ей. Вам не нужно ничего менять на своей стороне: unblocker: true продолжает указывать на ту версию браузера, которую мы проверили от начала до конца.
Впереди более сложная работа. Снятие отпечатков HTTP/3 уже появляется в управляемой защите от ботов, транспорт QUIC сложнее имитировать, чем старый транспорт, и начинается переход от статических наборов заголовков к по-настоящему динамической эмуляции. Защищенные сайты перешли на проверку порядка кадров HTTP/2, и разрыв между библиотекой, которая выглядит как браузер, и браузером будет сокращаться с обеих сторон. Мы напишем об этом, когда выпустим.