Files
robotex/client
protokeyandClaude Opus 5.5 5ed2cfbb3d feature: действие captcha value=image — капча-картинка через 2captcha (#109)
Снимок элемента картинки на текущей странице (без повторной загрузки 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>
2026-10-14 16:17:25 +04:00
..

robotex — Python-клиент Robotex API

Обвязка над HTTP API Robotex (docs/API.md): задачи v2 через очередь, синхронный /v1/solve, сессии с удержанием окна браузера. Синхронный Robotex и асинхронный AsyncRobotex с одинаковым интерфейсом. Зависимость одна — httpx.

Установка

pip install "robotex @ git+https://git.sokolab.xyz/s0k0l/robotex.git@v0.1.0#subdirectory=client"

или из wheel (make client-build в репозитории кладёт его в client/dist/):

pip install robotex-0.1.0-py3-none-any.whl

Быстрый старт

from robotex import Robotex, Action

with Robotex("https://robotex.example.com", api_key="rbx_...") as rx:
    result = rx.run(
        "https://example.com",
        [Action.wait_for("h1"), Action.inner_text("h1")],
        html=True,
    ).raise_for_status()
    print(result.results[0], result.user_agent, result.cookie("cf_clearance"))

base_url и api_key можно не передавать — тогда берутся из ROBOTEX_URL и ROBOTEX_API_KEY.

Остальные параметры запроса передаются именованными аргументами как есть: proxy, cookies, html, screenshot, timeout, captcha, captcha_type, disable_resources, blocked_domains, retries, wait, google_search и т. д.

Методы

Метод Что делает
run(url, actions, **opts) задача v2: поставить в очередь и дождаться результата (wait= секунд, по умолчанию 600)
submit(url, actions, **opts) только поставить; вернёт TaskRef с .status() и .wait()
solve(url, actions, **opts) синхронный /v1/solve; NoSlotsError, если свободных браузеров нет
session(session_id=None, idle_timeout=5) сессия: один профиль и окно, которое держится idle_timeout минут
close_session(session_id) закрыть окно сессии и освободить слот
health() слоты и воркеры

Вызовы без сессии каждый раз получают новый профиль браузера.

Сессии и удержание окна

with rx.session(idle_timeout=10) as s:
    s.run("https://site/login", [
        Action.typing("#login", "me"),
        Action.typing("#password", "secret"),
        Action.submit("button[type=submit]"),
    ]).raise_for_status()
    # без url — на текущей странице того же окна, без повторного запуска Chrome и антибота
    balance = s.run(actions=[Action.inner_text(".balance")]).results[0]
    saved = s.id
# на выходе из with окно закрывается (слот освобождается через секунду-две), профиль остаётся

again = rx.session(saved).run("https://site/account")   # продолжить сессию позже

Асинхронно

import asyncio
from robotex import AsyncRobotex, Action

async def main():
    async with AsyncRobotex() as rx:
        results = await asyncio.gather(*(rx.run(url, [Action.inner_text("h1")]) for url in urls))
        async with rx.session(idle_timeout=5) as s:
            await s.run("https://example.com")

Результат и ошибки

Result: status (ok/err), code, error, user_agent, cookies, actions (ActionResult), results (тексты действий по порядку), html, screenshot (base64, screenshot_bytes()), duration_ms, session_id.

Ошибка выполнения (challenge_failed, action_failed, request_failed) — это результат со status="err", исключения нет; raise_for_status() превращает её в ResultError (в e.result всё собранное: cookies, html, скриншот).

Исключения (все от RobotexError):

Исключение Когда
AuthError 401 — ключ не передан, неверен или отозван
InvalidRequest 422 — неверное действие, нет url без открытого окна и т. п.
NoSlotsError 503 у solve(); retry_after — через сколько секунд повторить
NotFound 404 — задача истекла или из другой сессии
TaskFailed задача failed/cancelled (например, упал воркер)
TaskTimeout wait истёк; задача продолжает выполняться, TaskRef.wait() можно повторить
ResultError raise_for_status() на результате со status="err"

Действия

Action.fill, typing, click, submit, mouse_move, delay(seconds), wait_for(selector, timeout=None), inner_html, inner_text, captcha(selector, kind), captcha_image(selector, target, **hints), pass_challenge(). Вместо Action можно передать dict в формате API: {"type": "click", "selector": "#a"}.

Капча-картинка («код с картинки»): снимок элемента уходит в 2captcha, ответ набирается в поле и возвращается в result. Подсказки: min_len, max_len, numeric (1 — цифры, 2 — буквы), lang, case_sensitive.

res = s.run(actions=[
    Action.captcha_image("#popup-signup img.captcha", '#popup-signup input[name="captcha"]', min_len=4),
    Action.submit("#popup-signup button[type=submit]"),
], captcha="<ключ 2captcha>")
code = res.results[0]