API — Распознавание капч

Отдельный слушатель, говорящий на протоколе anti-captcha.com: направьте на него стороннее ПО и решайте картинки, куки доступа, RCv2, CFt, GT и AW через свои прокси.

Что это

BlankTrail Proxy умеет принимать задачи на распознавание капч по протоколу anti-captcha.com. Это отдельный слушатель на своём порту: стороннее ПО, уже умеющее работать с этим протоколом, достаточно направить на ваш адрес вместо адреса сервиса распознавания.

Слушатель отдельный, а не маршруты на порту панели, по двум причинам. Официальные клиенты протокола бьют в корень хоста, то есть занимают корневые пути целиком. И капча-API вполне может понадобиться в локальной сети там, где панель управления не должна быть видна никому.

По умолчанию выключенКапча-API не поднимается, пока вы его не включите, и до включения порт не слушается вовсе. Это сделано намеренно: возможность, которой вы не пользуетесь, не должна открывать ни одного порта.

Как включить

Три поля в разделе captcha_api файла настроек. Рубильник и адрес можно поменять и в панели: «Настройки» → карточка «Капча-API».

captcha_api:
  enabled: true
  addr: ":8892"
  allow_lan: false
  max_concurrent: 10
  task_ttl: "5m"
  port_idle_timeout: "10m"
ПолеЧто делает
enabledПоднимать ли слушатель. По умолчанию нет.
addrАдрес слушателя. Пустой хост означает петлю, пока LAN не разрешён.
allow_lanПринимать запросы не с этой машины даже при выключенной общей «Разрешить LAN». Капча-API следует этой общей настройке панели, а поле открывает его сверх неё — отдельно от прокси-портов. В образе Docker включено.
max_concurrentПотолок одновременных задач. Ноль означает отсутствие потолка.
task_ttlСколько хранить готовый ответ после завершения задачи.
port_idle_timeoutЧерез сколько простоя закрывается порт, открытый под прокси задачи.
Применяется сразуРубильник и адрес в панели действуют немедленно: слушатель поднимается или гаснет по сохранению, а занятый адрес возвращается ошибкой прямо в панель. Так же, без перезапуска, действует и переключатель «Разрешить LAN». Правка самого файла настроек по-прежнему читается на старте — перезапустите приложение.

В контейнере

В образе всё, кроме рубильника, уже настроено: порт 8892 объявлен, поставляемые compose-файлы публикуют его на 127.0.0.1, а конфиг образа разрешает слушателю привязку не к петле. Остаётся включить — переменной либо прямо в панели. Перекрытие переменными одностороннее: они включают и задают, но не гасят включённое в конфиге.

docker run -d \
  -e BT_CAPTCHA_API_ENABLED=1 \
  -p 127.0.0.1:8892:8892 \
  ... blanktrail-proxy
Почему allow_lan в образе включёнВ контейнере запрос приходит с адреса моста Docker, а не с петли: с выключенным allow_lan пустой хост :8892 подставился бы на 127.0.0.1, и проброшенный порт отвечал бы отказом в соединении. BT_ALLOW_LAN при создании тома включает общую «Разрешить LAN» (вместе с паролем прокси), и капча-API ей следует. BT_CAPTCHA_API_ALLOW_LAN открывает капча-API отдельно от прокси-портов и нужен только со своим конфигом вместо образного.

Ключ и доступ

clientKey — это ключ API вашей панели, тот же самый. Отдельного ключа для капча-API нет: заводить вторую тайну с собственным хранением и ротацией ради одной поверхности незачем.

  • Ключ приезжает в ТЕЛЕ запроса, как того требует протокол, а не в заголовке.
  • Подбор ключа ограничивается: после серии неудач адрес получает отказ независимо от того, верен ли следующий ключ.
  • Запросы не с этой машины отвергаются, пока LAN не разрешён — общей настройкой «Разрешить LAN» или полем allow_lan, — включая getQueueStats и test.

Поддерживаемые типы задач

ТипЧто делает
ImageToTextTaskРаспознаёт текст на картинке локальной моделью.
AntiGateTaskПроходит защиту сайта и возвращает куки доступа.
RecaptchaV2TaskРешает RCv2 по адресу страницы и ключу сайта, через ваш прокси.
RecaptchaV2TaskProxylessТо же самое, но без вашего прокси — выход прямой.
TurnstileTaskПолучает токен CFt по адресу страницы и ключу сайта, через ваш прокси.
TurnstileTaskProxylessТо же самое без вашего прокси.
GeeTestTaskРешает GTv3 или v4 по параметрам сайта, через ваш прокси.
GeeTestTaskProxylessТо же самое без вашего прокси.
AmazonTaskПроходит стену AW и возвращает её токен, через ваш прокси.
AmazonTaskProxylessТо же самое без вашего прокси.

Прочие типы протокола отвечают ERROR_TASK_NOT_SUPPORTED. Это штатный ответ, а не сбой: клиент видит его сразу при создании задачи и может уйти к другому сервису, не тратя ожидания.

Варианты Proxyless решают с выхода самой установки — прямого адреса машины, на которой работает BlankTrail Proxy. Поля прокси, если они присланы, такие задачи не используют.

Как устроена работа

  1. Создаёте задачу через createTask и получаете числовой taskId.
  2. Опрашиваете getTaskResult, пока в ответе стоит processing.
  3. Получаете ready и объект решения — его состав зависит от типа задачи.
Ответ всегда HTTP 200Ошибка сообщается полями errorId и errorCode в теле, а не кодом HTTP — так устроен протокол. Клиент, увидевший не-200, счёл бы сервис упавшим и ушёл бы в свои повторы.

Выход и профиль

Все задачи, кроме ImageToTextTask, решает браузер решателя, и ходит он через порт продукта, открытый под прокси задачи. Это тот же путь, что у автоматического решения на прокси-порту. Запросы браузера уходят с выхода вашего прокси (у вариантов Proxyless — с выхода установки), с TLS- и HTTP/2-отпечатком и user-agent профиля этого порта. Токен или куки получены под той личностью, которую порт предъявляет сайту.

Порт открывается под пару «прокси плюс профиль» и живёт до простоя, заданного port_idle_timeout. Следующие задачи с тем же прокси и тем же профилем идут через него же.

Как выбирается профиль

Присланный userAgent не уезжает на провод. Он ВЫБИРАЕТ ближайший профиль по семейству браузера, мажорной версии и операционной системе, а на провод идёт user-agent этого профиля — вместе с согласованными с ним отпечатками TLS и HTTP/2.

Если userAgent не прислан или не распознан (Opera, Яндекс Браузер, Safari без токена Version/), порт получает Chrome для Windows новейшей версии из базы профилей — так же, как порт с профилем Chrome без заданной версии. У AntiGateTask и AmazonTask поля userAgent нет, и они всегда идут на этом профиле.

Используйте userAgent из ответаВ решении поле userAgent содержит ФАКТИЧЕСКИЙ user-agent, под которым добыт токен или куки. Подставьте в свой запрос именно его. Чужой заголовок поверх нашего провода — это ровно то расхождение, которое продукт устраняет: выдав его, капча-API стал бы источником примет вместо их сокрытия.

Каждая такая задача — попытка в карточке Challenge Breaker на дашборде, наравне с решениями на прокси-портах.

Распознавание картинки

Картинка передаётся в base64. Ответ несёт распознанный текст в поле text.

{
  "clientKey": "YOUR_API_KEY",
  "task": {
    "type": "ImageToTextTask",
    "body": "iVBORw0KGgoAAAANSUhEUg..."
  }
}
Модель обучена на своёмЧиталка обучалась на текстовых капчах вендора RC. На капче другой рисовки точность заметно ниже, и это свойство модели, а не настройка: проверьте долю верных ответов на своём материале, прежде чем строить на ней процесс.

Куки доступа

AntiGateTask проходит защиту сайта и возвращает куки. Вместе с ними в ответе приезжает адрес порта, через который эти куки обязаны предъявляться.

{
  "clientKey": "YOUR_API_KEY",
  "task": {
    "type": "AntiGateTask",
    "websiteURL": "https://example.com/",
    "proxyType": "http",
    "proxyAddress": "203.0.113.7",
    "proxyPort": 8080,
    "proxyLogin": "user",
    "proxyPassword": "pass"
  }
}
Куки работают только через названный портВ решении есть поле fingerprint с адресом blanktrail.replayProxy. Куки доступа привязаны к паре «выход плюс отпечаток», и предъявленные с другого адреса или из другого клиента они будут отвергнуты сайтом. Направьте свой запрос через этот порт — он уже открыт под ваш прокси и живёт до простоя, заданного port_idle_timeout.

RCv2

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

{
  "clientKey": "YOUR_API_KEY",
  "task": {
    "type": "RecaptchaV2Task",
    "websiteURL": "https://example.com/login",
    "websiteKey": "6Lc_aCMTAAAAA...",
    "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...",
    "proxyType": "http",
    "proxyAddress": "203.0.113.7",
    "proxyPort": 8080
  }
}

Ответ — gRecaptchaResponse и userAgent (пример — у метода getTaskResult ниже).

CFt

Задаче нужны адрес страницы и ключ сайта (websiteKey — строка вида 0x4AAAA…). Необязательные action, cData и chlPageData передаются виджету как есть. Вариант без вашего прокси — TurnstileTaskProxyless.

{
  "clientKey": "YOUR_API_KEY",
  "task": {
    "type": "TurnstileTaskProxyless",
    "websiteURL": "https://example.com/login",
    "websiteKey": "0x4AAAAAAA...",
    "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ..."
  }
}

Ответ — token и userAgent. Токен кладётся в поле cf-turnstile-response формы или отдаётся колбэку виджета; запрос с ним отправляйте с userAgent из ответа.

{
  "errorId": 0,
  "status": "ready",
  "solution": {
    "token": "0.Zk3bE8...",
    "userAgent": "Mozilla/5.0 ..."
  }
}
Страница проверки CF — не виджетЕсли сайт показывает промежуточную страницу «Just a moment…» и ждёт куку cf_clearance, решать нужно стену, а не виджет: это AntiGateTask, он возвращает куки. TurnstileTask отдаёт токен виджета, встроенного в страницу или форму. Если виджет не выдал токена, задача завершается ERROR_CAPTCHA_UNSOLVABLE — не позже чем через полторы минуты.

GT

Поддержаны GTv3 и GTv4; версию задаёт поле version (3 или 4, по умолчанию 3). Вариант без вашего прокси — GeeTestTaskProxyless.

  • v3: нужны gt и challenge сайта. challenge одноразовый — получайте его у сайта непосредственно перед созданием задачи. Необязательный geetestApiServerSubdomain задаёт сервер API, если сайт работает не с умолчанием GT.
  • v4: нужен captchaId — в поле gt или в initParameters.captcha_id. Остальные initParameters передаются в initGeetest4 как есть.
{
  "clientKey": "YOUR_API_KEY",
  "task": {
    "type": "GeeTestTaskProxyless",
    "websiteURL": "https://example.com/login",
    "gt": "0f1e2d3c4b5a69788796a5b4c3d2e1f0",
    "version": 4,
    "initParameters": {"riskType": "slide"},
    "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ..."
  }
}

Ответ v3 — challenge, validate и seccode; ответ v4 — captcha_id, lot_number, pass_token, gen_time и captcha_output. Вместе с ними приходит userAgent. Эти поля ваш запрос отправляет сайту, а сайт проверяет их у GT.

{
  "errorId": 0,
  "status": "ready",
  "solution": {
    "captcha_id": "0f1e2d3c4b5a69788796a5b4c3d2e1f0",
    "lot_number": "7c1b2a...",
    "pass_token": "a8d9...",
    "gen_time": "1790770800",
    "captcha_output": "Qx3k...",
    "userAgent": "Mozilla/5.0 ..."
  }
}
Решается слайдерРешатель проходит испытание со слайдером — перетаскивание детали пазла. На других видах испытания GT задача завершится ERROR_CAPTCHA_UNSOLVABLE.

AW

Задаче нужен адрес страницы, на которой сайт показывает стену AW. Поля websiteKey, iv, context, challengeScript и captchaScript принимаются для совместимости, но не нужны: всё это решатель берёт со страницы сам. Вариант без вашего прокси — AmazonTaskProxyless.

{
  "clientKey": "YOUR_API_KEY",
  "task": {
    "type": "AmazonTask",
    "websiteURL": "https://example.com/",
    "proxyType": "http",
    "proxyAddress": "203.0.113.7",
    "proxyPort": 8080,
    "proxyLogin": "user",
    "proxyPassword": "pass"
  }
}

Ответ — token и userAgent. token — значение куки aws-waf-token: поставьте её в свой запрос под этим именем и отправляйте его с userAgent из ответа. Поле ip в ответе getTaskResult — адрес выхода, с которого получен токен.

{
  "errorId": 0,
  "status": "ready",
  "solution": {
    "token": "a1b2c3d4-...:AAABk...",
    "userAgent": "Mozilla/5.0 ..."
  },
  "ip": "203.0.113.7"
}
Токен есть только там, где была стенаРешатель проходит стену, которую сайт показал на этом выходе. Если стены не было, куки нет, и задача завершается ERROR_CAPTCHA_UNSOLVABLE. Капча AWS внутри формы (wafType: widget) — не стена: она появляется по действию пользователя, поэтому такая задача сразу получает ERROR_TASK_NOT_SUPPORTED.

Методы

POST/createTaskтребует clientKey

Создаёт задачу и возвращает числовой taskId.

Ответ
{
  "errorId": 0,
  "taskId": 12
}
POST/getTaskResultтребует clientKey

Отдаёт состояние задачи, а по готовности — объект решения.

Запрос
{
  "clientKey": "YOUR_API_KEY",
  "taskId": 12
}
Ответ
{
  "errorId": 0,
  "status": "ready",
  "solution": {
    "gRecaptchaResponse": "03AGdBq26...",
    "userAgent": "Mozilla/5.0 ..."
  }
}
POST/getBalanceтребует clientKey

Отдаёт баланс. Биллинга у продукта нет, поэтому величина постоянная; ноль означает, что лицензия неактивна.

POST/getQueueStatsключ не требуется

Занятость: сколько задач в работе, насколько загружен пул решателя.

POST/reportIncorrectImageCaptchaтребует clientKey

Принимается для совместимости: обучать на отчётах продукт не умеет.

POST/reportIncorrectRecaptchaтребует clientKey

То же самое для RC.

POST/reportCorrectRecaptchaтребует clientKey

То же самое для подтверждения верного решения.

POST/testключ не требуется

Возвращает разобранное тело запроса. Полезно, когда чужой клиент шлёт не то.

Коды ошибок

Коды и их названия — протокольные: клиентские библиотеки сравнивают именно строку errorCode. Ниже те, которые выдаёт этот сервис.

errorIderrorCodeКогда
1ERROR_KEY_DOES_NOT_EXISTКлюч неверен либо адрес временно заблокирован за подбор.
2ERROR_NO_SLOT_AVAILABLEСвободных решателей нет прямо сейчас либо исчерпан потолок max_concurrent.
10ERROR_ZERO_BALANCEЛицензия неактивна: продлите её, задачи не принимаются.
11ERROR_IP_NOT_ALLOWEDЗапрос пришёл не с этой машины, а LAN не разрешён — ни общей «Разрешить LAN», ни полем allow_lan.
12ERROR_CAPTCHA_UNSOLVABLEРешить не удалось. Повтор возможен, но профиль останется прежним, пока порт не закроется по простою; если отказ повторяется, проверьте адрес страницы и параметры сайта: ключ, gt, challenge.
16ERROR_NO_SUCH_CAPCHA_IDЗадачи с таким taskId нет: она завершилась и была удалена по истечении task_ttl, либо принадлежит другому ключу.
23ERROR_TASK_NOT_SUPPORTEDТип задачи не поддержан, нужная модель не установлена или задача не того вида — например, капча AWS внутри формы (wafType: widget).
25ERROR_PROXY_CONNECT_REFUSEDВаш прокси отверг соединение. Чинить надо прокси, повторять задачу бесполезно.
26ERROR_PROXY_CONNECT_TIMEOUTДо вашего прокси не удалось дозвониться за отведённое время.
27ERROR_PROXY_READ_TIMEOUTВаш прокси принял соединение и замолчал.
49ERROR_PROXY_NOT_AUTHORISEDВаш прокси отверг логин или пароль.
Коды про прокси называют ВАШ проксиЧетыре кода 25, 26, 27 и 49 относятся к прокси, который вы прислали в задаче, а не к нашему выходу. Если прокси отвечает исправно, а решить не удалось, вы получите ERROR_CAPTCHA_UNSOLVABLE: свою неудачу мы на ваш прокси не списываем.

Границы

  • Задачи живут в памяти и перезапуск не переживают: после него taskId прежних задач отвечает ERROR_NO_SUCH_CAPCHA_ID.
  • Задача, не завершившаяся за отведённый бюджет, признаётся провалившейся и освобождает место в потолке.
  • Обратного вызова нет: поле callbackUrl принимается и игнорируется, результат забирается опросом.
  • Задачи на один и тот же сайт с одного прокси выполняются по очереди — это свойство защиты от повторов, а не потолок настроек.

Что дальше