# API Основной эндпоинт: `POST /v1/solve`. Открывает страницу в Chrome (через прокси клиента, если он задан), при необходимости проходит антибот (Cloudflare Turnstile, reCAPTCHA), выполняет список действий и возвращает cookies, результаты действий и, по запросу, HTML и скриншот. `GET /health` (и `GET /`) — `{"status": "ok", "browser_slots": N, "free_slots": M}`. > `X-API-Key` пока не проверяется ([#4](https://redmine.sokolab.xyz/issues/4)). ## Запрос ```http POST /v1/solve Content-Type: application/json X-API-Key: Cookie: session_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` | таймаут навигации | | `user_agent` | string | `null` | свой User-Agent. Задаётся профилю **один раз** — в первом запросе сессии; в следующих запросах этой сессии поле игнорируется. Без него профилю генерируется отпечаток (см. «Сессии») | | `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` | вставка значения в поле | | `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` в запросе | | `pass_challenge` | `selector` (локатор успеха, необязательно) | повторно пройти антибот, например после перехода на другую страницу; если не пройден — ошибка действия | ## Ответ Формат один для всех случаев: `status` — `"ok"` или `"err"`, при ошибке — `code` и `error`. Поля без значения не возвращаются. Успех (антибот пройден, действия выполнены), HTTP `200`: ```json { "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": "......", "duration_ms": 6405 } ``` | Поле | Описание | |---|---| | `status` | `"ok"` — антибот пройден и все действия выполнены, иначе `"err"` | | `code` | при `"err"`: причина, см. таблицу ниже | | `error` | при `"err"`: текст ошибки; для упавшего действия — `: <текст>` | | `user_agent` | UA браузера, с которым проходили антибот (нужен клиенту вместе с `cf_clearance`) | | `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` | все браузеры заняты (`BROWSER_SLOTS`), запрос не ставится в очередь | — | | `request_failed` | `200` | ошибка до действий: навигация, прокси, неизвестный `captcha_type` | `actions: []` | | `challenge_failed` | `200` | антибот не пройден за отведённое время, действия не выполнялись | cookies, html, screenshot | | `action_failed` | `200` | упало действие, выполнение остановлено на нём | cookies, html, screenshot, `actions` до упавшего включительно | Примеры: ```json {"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}], "...": "..."} ``` ```json {"status": "err", "code": "challenge_failed", "error": "cloudflare not passed: timeout (stage: checkbox)", "actions": [], "...": "..."} ``` ```json {"status": "err", "code": "no_slots", "error": "No slots available"} ``` ## Сессии Ответ ставит cookie `session_id` (UUID). Если передать её в следующем запросе, браузер откроется с тем же профилем (`extra/user_data_dir/`): cookies, localStorage, `user_agent` и отпечаток сохраняются, повторно проходить Cloudflare обычно не нужно. Без cookie или с некорректным значением (не UUID) запрос получает новый профиль. User-Agent и отпечаток профиля задаются при первом запросе сессии и дальше не меняются (`robotex_session.json` в каталоге профиля): - передан `user_agent` — профилю записывается он; - не передан — генерируется отпечаток десктопного Chrome на Linux (browserforge): UA с версией установленного Chrome, размер экрана и `devicePixelRatio` из реального распределения. Применяется нативной эмуляцией Chrome, без JS-подмены (она ломала прохождение Cloudflare). DPR влияет и на хеш canvas. Ограничение: canvas, WebGL и `hardwareConcurrency` у всех профилей одинаковые, поэтому примерно половина профилей совпадает по отпечатку (`make fp-check` показывает долю различий). Один профиль нельзя использовать в двух запросах одновременно: Chrome заблокирует каталог профиля. ## Производительность Каждый запрос запускает отдельный Chrome: около 0,6 ГБ памяти и до 3–4 ядер на пике при прохождении Cloudflare. Замеры и рекомендации по лимитам — в [Deployment.md](Deployment.md#нагрузка).