Снимок элемента картинки на текущей странице (без повторной загрузки src) уходит в 2captcha как обычная капча (method=base64), ответ набирается в поле target как у typing и возвращается в result действия. Необязательные подсказки: min_len, max_len, numeric, lang, case_sensitive. Клиент: Action.captcha_image. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
18 KiB
API
Как встраивать API в свой клиент (UA, прокси, сессии, повторы) — Usage.md.
Задача открывает страницу в Chrome (через прокси клиента, если он задан), при необходимости проходит антибот (Cloudflare Turnstile, reCAPTCHA), выполняет список действий и возвращает cookies, результаты действий и, по запросу, HTML и скриншот. Задачи выполняет сервис worker из очереди; API работает в двух режимах:
POST /v1/solve— синхронно: ответ приходит, когда задача выполнена;POST /v2/tasks+GET /v2/tasks/{id}— асинхронно, с возможностью держать окно браузера открытым между задачами (см. API v2).
GET /health (и GET /) — {"status": "ok", "browser_slots": N, "free_slots": M, "workers": [...]}: слоты всех
живых воркеров; workers — по каждому worker_id, browser_slots, free_slots, windows (открытые окна),
running (выполняемые задачи).
Авторизация
Все эндпоинты, кроме /health, требуют ключ клиента в заголовке X-API-Key. Без ключа, с неверным или отозванным
ключом — 401. Ключи выпускает администратор (make key-create name=<клиент>, см. Deployment.md).
Задача и окно сессии видны только клиенту, который их создал: с другим ключом GET /v2/tasks/{id} даёт 404, а
чужое открытое окно не используется.
Запрос
POST /v1/solve
Content-Type: application/json
X-API-Key: <key>
Cookie: session_id=<id> # необязательно, см. «Сессии»
{
"url": "https://freelancehunt.com/projects",
"proxy": "http://user:pass@host:port",
"captcha_type": "cloudflare",
"actions": [
{"type": "wait_for", "selector": "a[href*=\"/project/\"]", "timeout": 60}
],
"html": true,
"timeout": 120
}
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
url |
string | — | обязательно. Страница, которую открываем |
proxy |
string | null |
scheme://[user:pass@]host:port, схема http, https или socks5 (Chrome не поддерживает socks5 с логином/паролем). По exit-IP прокси выставляются locale и timezone браузера; без прокси — настройки браузера по умолчанию |
actions |
array | — | обязательно, может быть пустым. Действия, см. ниже |
captcha_type |
string | null |
провайдер антибота: cloudflare или recaptcha. Без него шаг антибота пропускается — для сайтов за Cloudflare обязательно |
captcha |
string | null |
ключ сервиса распознавания (2captcha), если антибот не проходится без решения капчи |
captcha_detect_locator |
string | null |
локатор, по которому определяется, что на странице антибот |
captcha_success_locator |
string | null |
локатор, по которому определяется, что антибот пройден |
html |
bool | false |
вернуть HTML страницы после выполнения действий |
screenshot |
bool | false |
вернуть скриншот видимой области (PNG, base64) после действий — в том числе при ошибке действия или антибота |
timeout |
int, с | 60 |
таймаут навигации |
cookies |
array | null |
cookies для установки до навигации, формат Playwright: {name, value, domain, path, expires, httpOnly, secure, sameSite} или {name, value, url}. Заменяют cookies профиля: перед установкой все cookies профиля удаляются ([] — просто очистить). Без поля cookies профиля сохраняются |
disable_resources |
bool | false |
не грузить картинки, шрифты, медиа |
blocked_domains |
array | null |
домены, запросы к которым блокируются |
retries |
int | 1 |
попыток навигации |
retry_delay |
float, с | 1.0 |
пауза между попытками |
wait |
int, мс | 0 |
пауза после загрузки страницы |
google_search |
bool | false |
выставить Referer как переход из поиска Google |
Действия
Выполняются по порядку после прохождения антибота. Если антибот не пройден, действия не выполняются
(code: challenge_failed). На первой ошибке действия выполнение останавливается.
Обязательные поля проверяются до запуска браузера: неизвестный type, нет selector/value, captcha без ключа
в запросе, неверный proxy — ответ 422 с описанием в detail (стандартный формат FastAPI).
type |
Поля | Что делает |
|---|---|---|
wait_for |
selector, timeout (1–7200 с, по умолчанию 30) |
ждёт появления элемента; при таймауте — ошибка действия |
click |
selector |
клик по элементу |
submit |
selector |
клик и ожидание навигации |
fill |
selector, value |
мгновенная вставка значения в поле |
typing |
selector, value |
ввод как у человека: подвод курсора, клик, очистка поля, посимвольный набор с паузами 50–200 мс; медленнее fill, но не выдаёт автоматизацию |
inner_text |
selector |
возвращает текст элемента (HTML без тегов) в result |
mouse_move |
selector |
наведение курсора на элемент; нет элемента — ошибка selector not found |
delay |
value (секунды строкой, 0–600) |
пауза |
inner_html |
selector |
возвращает HTML элемента в result; нет элемента — ошибка selector not found |
captcha |
selector, value (тип: cloudflare, recaptcha, hcaptcha) |
решить капчу внутри страницы через 2captcha, нужен captcha в запросе |
captcha (value: "image") |
selector (картинка), target (поле ввода); подсказки необязательны: min_len, max_len (1–20), numeric, lang, case_sensitive |
капча-картинка «код с картинки»: скриншот элемента selector на текущей странице (без повторной загрузки, код не меняется) уходит в 2captcha, ответ набирается в target как у typing и возвращается в result. Не решена или таймаут 2captcha — ошибка действия. numeric: 1 — только цифры, 2 — только буквы, 3 — цифры или буквы, 4 — и цифры, и буквы |
pass_challenge |
selector (локатор успеха, необязательно) |
повторно пройти антибот, например после перехода на другую страницу; если не пройден — ошибка действия |
Капча-картинка в форме регистрации — решить, затем отправить форму. Если сайт отклонил код и показал новую картинку,
повторите задачу v2 в открытом окне сессии (browser_idle_timeout): страница не перезагружается.
{"captcha": "<ключ 2captcha>", "browser_idle_timeout": 5, "actions": [
{"type": "captcha", "selector": "#popup-signup img.captcha", "value": "image",
"target": "#popup-signup input[name=\"captcha\"]", "min_len": 4, "max_len": 6},
{"type": "submit", "selector": "#popup-signup button[type=submit]"}
]}
Ответ
Формат один для всех случаев: status — "ok" или "err", при ошибке — code и error. Поля без значения не
возвращаются.
Успех (антибот пройден, действия выполнены), HTTP 200:
{
"status": "ok",
"user_agent": "Mozilla/5.0 (X11; Linux x86_64) ... Chrome/155.0.0.0 Safari/537.36",
"cookies": [{"name": "cf_clearance", "value": "...", "domain": ".freelancehunt.com", "...": "..."}],
"actions": [
{"type": "wait_for", "ok": true, "duration_ms": 14}
],
"html": "<head>...</head><body>...</body>",
"duration_ms": 6405
}
| Поле | Описание |
|---|---|
status |
"ok" — антибот пройден и все действия выполнены, иначе "err" |
code |
при "err": причина, см. таблицу ниже |
error |
при "err": текст ошибки; для упавшего действия — <type>: <текст> |
user_agent |
родной UA браузера, с которым проходили антибот. Используйте его в своём HTTP-клиенте вместе с cf_clearance (см. Usage.md) |
cookies |
все cookies контекста |
actions |
по элементу на выполненное действие: type, ok, result (результат или текст ошибки), duration_ms |
html |
только при "html": true |
screenshot |
только при "screenshot": true: PNG в base64 |
duration_ms |
общее время обработки запроса |
code |
HTTP | Когда | Что ещё есть в ответе |
|---|---|---|---|
no_slots |
503 + Retry-After |
только /v1/solve: все слоты браузеров заняты, или воркер не взял задачу за V1_QUEUE_WAIT секунд (задача отменяется) |
— |
request_failed |
200 |
ошибка до действий: навигация, прокси, неизвестный captcha_type |
actions: [] |
challenge_failed |
200 |
антибот не пройден за отведённое время, действия не выполнялись | cookies, html, screenshot |
action_failed |
200 |
упало действие, выполнение остановлено на нём | cookies, html, screenshot, actions до упавшего включительно |
Примеры:
{"status": "err", "code": "action_failed", "error": "inner_html: selector not found: #missing",
"actions": [{"type": "inner_html", "ok": false, "result": "selector not found: #missing", "duration_ms": 26}], "...": "..."}
{"status": "err", "code": "challenge_failed", "error": "cloudflare not passed: timeout (stage: checkbox)", "actions": [], "...": "..."}
{"status": "err", "code": "no_slots", "error": "No slots available"}
Сессии
Ответ ставит cookie session_id (UUID). Если передать её в следующем запросе, браузер откроется с тем же профилем
(extra/user_data_dir/<session_id>): cookies, localStorage и отпечаток сохраняются, повторно проходить Cloudflare
обычно не нужно. Без cookie или с некорректным значением (не UUID) запрос получает новый профиль.
Сессии изолированы друг от друга: у каждой свой профиль Chrome — cookies, localStorage, кэш.
Отпечаток профиля генерируется при первом запросе сессии и дальше не меняется (robotex_session.json в каталоге
профиля):
- размер экрана и
devicePixelRatioдесктопного Chrome на Linux из реального распределения (browserforge) — нативной эмуляцией Chrome; - шум canvas: свой seed у каждого профиля, поэтому хеш canvas у профилей разный, а внутри профиля стабильный.
Меняется младший бит у редких непрозрачных пикселей при чтении canvas (
toDataURL,toBlob,getImageData); пустой canvas не меняется.
Остальное — WebGL, hardwareConcurrency, шрифты, UA — не подменяется: это родные значения Chrome, за маскировку
автоматизации отвечает Patchright. Полная JS-подмена отпечатка ломала прохождение Cloudflare.
User-Agent и размер окна запросом не задаются — это родные значения браузера (почему — Usage.md).
Поле user_agent в запросе даёт 422.
Задачи одной сессии выполняются по очереди: профиль Chrome нельзя открыть дважды. Вторая задача ждёт, пока закончится первая.
API v2
Асинхронный режим: задача ставится в очередь, клиент опрашивает её по ссылке. Тело задачи — как у /v1/solve, плюс:
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
browser_idle_timeout |
int, мин | 0 |
держать окно браузера открытым после задачи столько минут простоя, 0–120. 0 — закрыть сразу, как в v1 |
url |
string | null |
необязателен, если окно сессии открыто: тогда действия выполняются на текущей странице, без навигации |
POST /v2/tasks
POST /v2/tasks
Content-Type: application/json
Cookie: session_id=<id> # необязательно
{"url": "https://freelancehunt.com/projects", "captcha_type": "cloudflare", "actions": [], "browser_idle_timeout": 10}
Ответ 202 и cookie session_id:
{"task_id": "0b9c…", "status": "queued", "url": "/v2/tasks/0b9c…"}
Без url и без открытого окна сессии — 422.
GET /v2/tasks/{id}
Только с cookie session_id той сессии, в которой задача создана; иначе, а также для несуществующей или истёкшей
задачи — 404.
{"task_id": "0b9c…", "status": "done", "result": {"status": "ok", "user_agent": "…", "cookies": […], "actions": […], "duration_ms": 7120}}
status |
Значение |
|---|---|
queued |
ждёт свободного слота браузера |
running |
выполняется |
done |
готово, ответ в result — в том же формате, что ответ /v1/solve (со своим status ok/err) |
failed |
задачу не удалось выполнить (например, воркер упал дважды), причина в error |
Результат хранится RESULT_TTL_HOURS часов (по умолчанию 24), затем 404. Опрашивать раз в 0,5–2 секунды.
Окно браузера между задачами
С browser_idle_timeout > 0 Chrome сессии не закрывается после задачи. Следующая задача с той же cookie
session_id выполняется в этом окне: без запуска Chrome и обычно без повторного антибота, а без url — прямо на
текущей странице (например, продолжить заполнение формы). Каждая задача в окно заново отсчитывает простой — по
своему browser_idle_timeout; задача с 0 закрывает окно после себя.
- Открытое окно занимает слот браузера, пока не закроется. Не держите окна дольше, чем нужно.
- Задача с другим
proxy, чем у открытого окна, перезапускает Chrome (прокси задаётся при запуске). cookiesв задаче заменяют cookies открытого окна, как и при запуске.- Если задача в окне упала с
request_failed, окно закрывается; следующая задача откроет его заново из профиля.
DELETE /v2/sessions/current
Закрыть окно сессии (по cookie session_id) досрочно и освободить слот. Если в окне идёт задача — сразу после неё.
Ответ {"closed": true}, или {"closed": false}, если окна нет.
Производительность
Каждое окно — отдельный Chrome: около 0,6 ГБ памяти и до 3–4 ядер на пике при прохождении Cloudflare. Замеры и рекомендации по лимитам — в Deployment.md.