Files
robotex/client/README.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

105 lines
5.3 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.
# robotex — Python-клиент Robotex API
Обвязка над HTTP API Robotex (docs/API.md): задачи v2 через очередь, синхронный `/v1/solve`, сессии с удержанием окна
браузера. Синхронный `Robotex` и асинхронный `AsyncRobotex` с одинаковым интерфейсом. Зависимость одна — `httpx`.
## Установка
```bash
pip install "robotex @ git+https://git.sokolab.xyz/s0k0l/robotex.git@v0.1.0#subdirectory=client"
```
или из wheel (`make client-build` в репозитории кладёт его в `client/dist/`):
```bash
pip install robotex-0.1.0-py3-none-any.whl
```
## Быстрый старт
```python
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()` | слоты и воркеры |
Вызовы без сессии каждый раз получают новый профиль браузера.
## Сессии и удержание окна
```python
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") # продолжить сессию позже
```
## Асинхронно
```python
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)`, `pass_challenge()`. Вместо `Action` можно передать dict в формате
API: `{"type": "click", "selector": "#a"}`.