← Все статьи

Внутри профиля браузера: как на самом деле работает `unblocker: true`

Один флаг переключает три параметра: реальные заголовки браузера, соответствующую сигнатуру соединения и автоматическую распаковку для gzip и brotli. Вот что он делает и зачем нужен.

Большинство скраперов блокируются еще до чтения первого 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, и разрыв между "библиотекой, похожей на браузер" и "настоящим браузером" будет сокращаться с обеих сторон. Мы напишем об этом, когда выкатим релиз.