Files
robotex/docs/Usage.md
T
protokeyandClaude Opus 5.5 cb85e5f3ab Python-клиент robotex: sync/async, сессии, задачи v2, ошибки
Пакет в client/ (зависимость — httpx), установка через pip из git или
wheel (make client-build). Тесты против api и воркера из harness.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 22:18:40 +04:00

9.3 KiB
Raw Blame History

Использование API: практики для клиентов

Как встроить Robotex в свой парсер или бота, чтобы антибот проходился стабильно, а полученные cookies работали. Справочник по полям и ответам — 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 навигация не удалась: обычно прокси недоступен или сайт не отвечает
401 нет ключа в X-API-Key, ключ неверный или отозван
422 ошибка в запросе: описание в detail

Успех — строго status == "ok".

Таймауты

Прохождение антибота может занять до 2 минут, плюс навигация (timeout) и действия. Таймаут вашего HTTP-клиента к Robotex ставьте не меньше timeout + 120 с + сумма таймаутов действий. Так же настройте reverse proxy перед сервисом.

Python-клиент

Для Python есть готовый пакет robotex (client/README.md): задачи, сессии с удержанием окна, ожидание результата, ошибки в виде исключений, sync и async.

from robotex import Robotex, Action

with Robotex("https://app.robotex.sokolab.xyz", api_key="rbx_...") as rx:
    result = rx.run("https://example.com", [Action.inner_text("title")]).raise_for_status()

Пример (Python, httpx)

import httpx

ROBOTEX = "https://app.robotex.sokolab.xyz"
PROXY = "http://user:pass@host:port"

robotex = httpx.Client(base_url=ROBOTEX, timeout=300, headers={"X-API-Key": "rbx_..."})


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