Большинство скраперов блокируются еще до чтения первого header.
Сервер анализирует сигнатуру подключения вашего клиента на сетевом уровне и определяет, реальный ли это браузер или библиотека, которая под него маскируется. Python requests, net/http в Go, обычный curl: все они отдают характерный фингерпринт в момент первого рукопожатия. Ресурсы с продвинутой защитой (Datadome, Akamai, Imperva, управляемые правила Cloudflare) сбрасывают соединение или возвращают challenge-страницу еще до того, как ваш User-Agent будет обработан.
Именно эту задачу решает unblocker: true в FourA. За последний месяц мы доработали компоненты, обеспечивающие его стабильную работу.
Что нового
unblocker: true представляет собой один флаг для любого вызова /api/single. При его активации выполняются три действия: подставляется набор браузерных header, запрос отправляется через транспортный уровень, идентичный реальному браузеру, и распаковывается любой ответ сервера (gzip, brotli, deflate). Первые две функции были доступны еще в бете. Третья (автоматическая распаковка brotli) вышла 25 марта, а на следующий день была добавлена фиксация версий для синхронизации header и параметров транспорта.
Принцип работы
Пример структуры запроса:
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. Порядок имеет значение. Реальные браузеры отправляют их в определенной последовательности, и библиотеки детекта это проверяют.
Сигнатура соединения. Наш транспорт воспроизводит побайтовую структуру актуальной браузерной сессии: тот же порядок расширений, те же предпочтения шифров, те же особенности handshake. Стандартный curl, Python requests и Go net/http создают сигнатуры, которые защищенная инфраструктура детектирует за миллисекунды.
Автоматическая декомпрессия. Когда включен unblocker, мы выставляем Accept-Encoding в gzip, deflate, br, и транспорт распаковывает тело ответа. Вы получаете декодированную строку (или Buffer, если передан returnBuffer: true). Никакой ручной обработки brotli, никаких несоответствий заголовков и тела ответа, когда сайт выбирает deflate вместо gzip.
Почему фиксация версий важна
Сигнатуры соединения привязаны к конкретным версиям. Сетевые детали браузера в этом месяце отличаются от прошлого, и сайт с качественным фингерпринтингом заметит расхождение. Мы жестко связываем все подвижные компоненты, чтобы заголовки, объекты navigator и сигнатура соединения сообщали одну и ту же версию браузера.
Это звучит сложно, и так оно и есть. Мы сами столкнулись с рассинхронизацией во время мартовской миграции монорепозитория, когда один компонент обновился автоматически, а остальные отстали. Исправление заняло два коммита: зафиксировать версию компонента и никогда не доверять пакетному менеджеру синхронизацию таких зависимостей.
Результаты
Во внутренних тестах на сайтах, проверяющих клиента (финансы, путешествия, крупный e-commerce), разница между unblocker: false и unblocker: true означает разницу между страницей проверки и кодом 200. Обычный HTTP клиент часто сразу получает 403. Тот же URL с unblocker: true возвращает страницу, потому что запрос выглядит в точности как указанный браузер.
Но для сайтов без фингерпринтинга (большинство публичных API, старые CMS, любые ресурсы только с ограничением по IP rate limit) отключение unblocker работает нормально и экономит несколько миллисекунд на согласовании соединения. Используйте его там, где это действительно нужно.
Для опытных разработчиков
Несколько полезных паттернов.
Используйте unblocker вместе с резидентным proxy, когда целевой ресурс проверяет репутацию IP. Датацентровые IP в сочетании с идеальной сигнатурой соединения все равно вызовут блокировку по черным спискам ASN. Наш proxy endpoint (/api/proxy) выполняет ротацию по целевому домену, поэтому обычно достаточно добавить "proxy": "residential" в запрос.
Пропускайте unblocker при обращении к JSON API, которым не важен браузер. Лишние заголовки могут выглядеть подозрительно для API, ожидающего программного клиента, например бэкенда при вызове собственного микросервиса.
Если сайт проверяет посетителя с помощью JavaScript перед отображением страницы, одного unblocker будет недостаточно. Вам понадобится браузерный endpoint, который выполняет JavaScript страницы в полноценном браузере. Это отдельный продукт с другими тарифами в кредитах, и мы описали его в статье Задачи для браузера: как парсить сайты с обилием JavaScript.
Вы также можете комбинировать unblocker с блоком validate, чтобы отклонять response, которые формально возвращают 200, но содержат страницу проверки:
{
"url": "https://example.com/products",
"method": "GET",
"unblocker": true,
"validate": {
"data": { "fail": ["captcha", "Access Denied"] }
}
}
Это превращает скрытые сбои в классифицированные ошибки, что важно для отслеживания success rate в dashboard.
Что дальше
Браузеры выпускают стабильные релизы каждые четыре недели. Мы обновляем наш стек синхронно с ними. Вам ничего не нужно менять на своей стороне: unblocker: true продолжает указывать на ту версию браузера, которую мы проверили end-to-end.
Впереди более сложная работа. Проверки HTTP/3 уже появляются на крупных сайтах, QUIC transport сложнее воспроизвести, чем старый транспортный уровень, и начинается переход от статических наборов header к по-настоящему динамической эмуляции. Защищенные сайты перешли на проверку порядка фреймов HTTP/2, и разрыв между "библиотекой, похожей на браузер" и "настоящим браузером" будет сокращаться с обеих сторон. Мы напишем об этом, когда выкатим релиз.