Files
robotex/docs/API.md
T
protokeyandClaude Opus 5.5 58100fa45d feature: UA и отпечаток задаются профилю один раз, cookies запроса заменяют профильные
- user_agent записывается в профиль при первом запросе сессии, дальше игнорируется (#87)
- переданные cookies заменяют cookies профиля (clear_cookies перед add_cookies) (#88)
- без user_agent профилю генерируется отпечаток browserforge (Linux Chrome): UA с версией
  установленного Chrome, экран и devicePixelRatio; только нативная эмуляция, без JS (#89)
- make fp-check: проверка, что отпечаток применяется и стабилен, и доля различий профилей

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 17:23:01 +04:00

148 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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: <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` | таймаут навигации |
| `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": "<head>...</head><body>...</body>",
"duration_ms": 6405
}
```
| Поле | Описание |
|---|---|
| `status` | `"ok"` — антибот пройден и все действия выполнены, иначе `"err"` |
| `code` | при `"err"`: причина, см. таблицу ниже |
| `error` | при `"err"`: текст ошибки; для упавшего действия — `<type>: <текст>` |
| `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/<session_id>`): 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#нагрузка).