- Сервис api (FastAPI, без Chrome): POST /v2/tasks, GET /v2/tasks/{id} (доступ по cookie
сессии), DELETE /v2/sessions/current; /v1/solve — прежний контракт поверх очереди.
- Сервис worker (dramatiq + RabbitMQ): слоты браузера, окна сессий между задачами
(browser_idle_timeout 0–120 мин, простой — TTL ключа в Redis), heartbeat.
- Маршрутизация задач сессии в персональную очередь воркера с открытым окном.
- Redis: задачи, результаты (RESULT_TTL_HOURS), окна, воркеры. Прокси и ключ 2captcha
в Redis не сохраняются.
- Движок: AsyncStealthySession.run() — действия на текущей странице без навигации.
- Два образа (robotex-api, robotex-worker), compose с rabbitmq и redis,
make up/down/logs/smoke, релиз собирает все образы.
- Тесты: api + worker в одном процессе (fakeredis), настоящий воркер dramatiq на
StubBroker, браузерные тесты на новой схеме, smoke для запущенного стенда.
- Документация: README, API (v2), Deployment, Usage.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
126 lines
8.7 KiB
Markdown
126 lines
8.7 KiB
Markdown
# Использование API: практики для клиентов
|
||
|
||
Как встроить Robotex в свой парсер или бота, чтобы антибот проходился стабильно, а полученные cookies работали.
|
||
Справочник по полям и ответам — [API.md](API.md).
|
||
|
||
## Основной сценарий
|
||
|
||
Robotex проходит антибот в настоящем браузере и отдаёт то, с чем клиент дальше ходит на сайт **своим HTTP-клиентом**:
|
||
|
||
1. `POST /v1/solve` с `url`, своим `proxy` и `captcha_type`.
|
||
2. Из ответа взять `cookies` (среди них `cf_clearance`) и **`user_agent`**.
|
||
3. Дальше ходить на сайт своим HTTP-клиентом:
|
||
- с **тем же User-Agent**, что пришёл в ответе;
|
||
- через **тот же прокси** (тот же exit-IP);
|
||
- с полученными cookies.
|
||
4. Когда сайт снова отвечает челленджем (обычно `403` и страница «Just a moment…») или истекает `cf_clearance`
|
||
(поле `expires` у cookie) — повторить `/v1/solve` **в той же сессии** (cookie `session_id`).
|
||
|
||
`cf_clearance` выдаётся конкретному браузеру: Cloudflare связывает его с User-Agent и, как правило, с IP. С другим UA
|
||
или через другой прокси cookie не сработает, и сайт снова покажет челлендж.
|
||
|
||
## Что задаёт сервис, а не клиент
|
||
|
||
User-Agent, размер окна и экран, отпечаток браузера **не настраиваются запросом** — их определяет сам браузер.
|
||
Клиент подстраивается под ответ, а не наоборот.
|
||
|
||
Почему так: подменить можно только часть признаков. Строка UA меняется, но `navigator.userAgentData`, client hints и
|
||
поведение движка остаются от реального Chrome, и Cloudflare видит расхождение. Замер на Chrome 155 / Linux:
|
||
|
||
| User-Agent в браузере | Cloudflare |
|
||
|---|---|
|
||
| родной (Linux Chrome 155) | пройден 3 из 3, 7–9 с |
|
||
| Linux Chrome 147 | не пройден, 3 из 3 |
|
||
| Windows Chrome 155 | не пройден |
|
||
|
||
Поэтому параметр `user_agent` убран из запроса (передача даёт `422`). Раньше по той же причине был убран параметр
|
||
размера окна. Каждому профилю сервис сам генерирует правдоподобный отпечаток (экран и `devicePixelRatio` из
|
||
реального распределения) и применяет его средствами Chrome.
|
||
|
||
UA в ответе может измениться, когда на сервере обновится Chrome. Не храните UA у себя навсегда — берите его из
|
||
последнего ответа.
|
||
|
||
## Сессии
|
||
|
||
- Ответ ставит cookie `session_id`. Передавайте её в следующих запросах: профиль браузера сохраняется (cookies,
|
||
localStorage, отпечаток), и повторно проходить антибот обычно не нужно — запрос заметно быстрее.
|
||
- Одна сессия — один «человек»: держите для неё **один и тот же прокси**. Смена exit-IP внутри сессии выглядит
|
||
подозрительно и обнуляет `cf_clearance`.
|
||
- Задачи одной сессии выполняются по очереди: вторая ждёт, пока закончится первая.
|
||
- Для параллельной работы заводите несколько сессий, каждую со своим прокси.
|
||
|
||
## Синхронно или через задачи
|
||
|
||
- `/v1/solve` — проще: один запрос, один ответ. Держите соединение открытым до 3–4 минут (см. «Таймауты»).
|
||
- `/v2/tasks` — запрос возвращается сразу, результат забираете по ссылке `GET /v2/tasks/{id}` с той же cookie
|
||
`session_id`. Подходит, когда соединение нельзя держать долго, и для многошаговых сценариев.
|
||
|
||
Многошаговый сценарий (войти, затем несколько раз что-то сделать на сайте) — с удержанием окна:
|
||
|
||
1. `POST /v2/tasks` с `url` и `browser_idle_timeout`: окно останется открытым на это число минут простоя.
|
||
2. Следующие задачи с той же cookie `session_id` и тем же `proxy` выполняются в открытом окне: без запуска Chrome
|
||
и повторного антибота. Без `url` — на текущей странице.
|
||
3. В конце — `DELETE /v2/sessions/current` или задача с `browser_idle_timeout: 0`: окно закроется и освободит слот.
|
||
|
||
Открытое окно занимает слот браузера, поэтому ставьте простой не больше, чем пауза между вашими шагами.
|
||
|
||
## Cookies
|
||
|
||
- Переданные в запросе `cookies` **заменяют** cookies профиля целиком. Не передали — профиль сохраняет свои.
|
||
- Для постоянных cookies указывайте `expires` (unix-время). Cookie без `expires` — сессионная и пропадёт, как
|
||
только закроется окно браузера (после задачи без `browser_idle_timeout`).
|
||
- Обычно передавать cookies не нужно: профиль сам хранит то, что выдал сайт. Передавайте, только если сайт ведёт
|
||
себя по-разному в зависимости от cookies (например, авторизация, полученная вне Robotex).
|
||
|
||
## Ошибки и повторы
|
||
|
||
| Ответ | Что делать |
|
||
|---|---|
|
||
| `503`, `code: no_slots` | `/v1/solve`: все браузеры заняты — повторить через `Retry-After` секунд. Задачи v2 в этом случае ждут в очереди |
|
||
| `challenge_failed` | антибот не пройден за отведённое время: повторить в той же сессии; при повторных неудачах — сменить прокси (и сессию) |
|
||
| `action_failed` | упало действие: смотрите `error` и `actions[].result`; для отладки повторите с `"screenshot": true` |
|
||
| `request_failed` | навигация не удалась: обычно прокси недоступен или сайт не отвечает |
|
||
| `422` | ошибка в запросе: описание в `detail` |
|
||
|
||
Успех — строго `status == "ok"`.
|
||
|
||
## Таймауты
|
||
|
||
Прохождение антибота может занять до 2 минут, плюс навигация (`timeout`) и действия. Таймаут вашего HTTP-клиента
|
||
к Robotex ставьте не меньше `timeout` + 120 с + сумма таймаутов действий. Так же настройте reverse proxy перед сервисом.
|
||
|
||
## Пример (Python, httpx)
|
||
|
||
```python
|
||
import httpx
|
||
|
||
ROBOTEX = "https://app.robotex.sokolab.xyz"
|
||
PROXY = "http://user:pass@host:port"
|
||
|
||
robotex = httpx.Client(base_url=ROBOTEX, timeout=300)
|
||
|
||
|
||
def solve(url: str) -> dict:
|
||
resp = robotex.post("/v1/solve", json={
|
||
"url": url,
|
||
"proxy": PROXY,
|
||
"captcha_type": "cloudflare",
|
||
}) # session_id сохраняется в cookies клиента robotex и уходит в следующих запросах
|
||
data = resp.json()
|
||
if data.get("status") != "ok":
|
||
raise RuntimeError(f"{data.get('code')}: {data.get('error')}")
|
||
return data
|
||
|
||
|
||
solution = solve("https://freelancehunt.com/projects")
|
||
|
||
site = httpx.Client(
|
||
proxy=PROXY, # тот же прокси
|
||
headers={"User-Agent": solution["user_agent"]}, # тот же UA
|
||
cookies={c["name"]: c["value"] for c in solution["cookies"]},
|
||
)
|
||
page = site.get("https://freelancehunt.com/projects")
|
||
if page.status_code == 403:
|
||
solution = solve("https://freelancehunt.com/projects") # та же сессия, обновить cf_clearance
|
||
```
|