feat: url текущей страницы в ответе задачи (#116)

SPA меняет адрес без навигации (страница созданной заявки и т.п.): ответ v1/v2 отдаёт page.url
после действий, клиент 0.2.1 - Result.url. Документация и unit-тесты.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
protokeyandClaude Opus 5.5 committed 2026-10-24 22:02:08 +04:00
1 parent 95b5057d9f
commit f21483489a
9 files changed
+14 -2

No files matched your search

+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "robotex"
version = "0.2.0"
version = "0.2.1"
description = "Python-клиент Robotex API: браузер с обходом антиботов, задачи v2 и окна сессий"
readme = "README.md"
requires-python = ">=3.10"
+1 -1
View File
@@ -21,7 +21,7 @@ from robotex.errors import (
)
from robotex.models import ActionResult, Result, Task
__version__ = "0.2.0"
__version__ = "0.2.1"
__all__ = [
"Action", "ActionResult", "AsyncRobotex", "AsyncSession", "AsyncTaskRef", "AuthError", "InvalidRequest",
+2
View File
@@ -24,6 +24,7 @@ class Result:
code: str | None = None
error: str | None = None
user_agent: str | None = None
url: str | None = None
cookies: list[dict[str, Any]] = field(default_factory=list)
actions: list[ActionResult] = field(default_factory=list)
html: str | None = None
@@ -59,6 +60,7 @@ class Result:
code=data.get("code"),
error=data.get("error"),
user_agent=data.get("user_agent"),
url=data.get("url"),
cookies=data.get("cookies") or [],
actions=[ActionResult.from_dict(a) for a in data.get("actions") or []],
html=data.get("html"),
+1
View File
@@ -121,6 +121,7 @@ Cookie: session_id=<id> # необязательно, см. «Сесси
| `status` | `"ok"` — антибот пройден и все действия выполнены, иначе `"err"` |
| `code` | при `"err"`: причина, см. таблицу ниже |
| `error` | при `"err"`: текст ошибки; для упавшего действия — `<type>: <текст>` |
| `url` | адрес страницы после выполнения действий (SPA меняет его без навигации, например на страницу созданной заявки) |
| `user_agent` | родной UA браузера, с которым проходили антибот. Используйте его в своём HTTP-клиенте вместе с `cf_clearance` (см. [Usage.md](Usage.md)) |
| `cookies` | все cookies контекста |
| `actions` | по элементу на выполненное действие: `type`, `ok`, `result` (результат или текст ошибки), `duration_ms` |
+2
View File
@@ -161,6 +161,8 @@ class SolveResponse(BaseModel):
code: Literal["no_slots", "request_failed", "challenge_failed", "action_failed"] | None = None
error: str | None = None
user_agent: str | None = None
# адрес страницы после выполнения действий
url: str | None = None
cookies: list[dict[str, Any]] | None = None
actions: list[ActionResult] = []
html: str | None = None
+3
View File
@@ -138,6 +138,8 @@ def make_page_action(payload: TaskRequest):
"html": await page.inner_html("html"),
"screenshot": screenshot,
"user_agent": await page.evaluate("() => navigator.userAgent"),
# адрес страницы после действий: SPA меняет его без навигации (номер заявки и т.п.)
"url": page.url,
}
return page_action
@@ -149,6 +151,7 @@ def build_result(payload: TaskRequest, result: dict) -> dict:
response = {
"status": "ok",
"user_agent": result["user_agent"],
"url": result.get("url"),
"cookies": result["cookies"],
"actions": result["actions"],
}
+2
View File
@@ -21,6 +21,8 @@ class FakeContext:
class FakePage:
url = "https://example.com/after-actions"
def __init__(self, context):
self.context = context
+1
View File
@@ -69,6 +69,7 @@ def test_run(rx, monkeypatch):
result = rx.run("https://example.com", [Action.inner_text("h1")], html=True)
assert result.ok and result.results == ["Example"]
assert result.html == "<body>page</body>" and result.user_agent == "UA/engine"
assert result.url == "https://example.com/after-actions"
assert result.cookie("cf_clearance") == "secret-cookie"
assert result.session_id
+1
View File
@@ -25,6 +25,7 @@ def test_ok(env, monkeypatch):
assert data["status"] == "ok"
assert "code" not in data and "error" not in data
assert data["user_agent"] == "UA/engine"
assert data["url"] == "https://example.com/after-actions"
assert data["actions"] == [{"type": "wait_for", "ok": True, "duration_ms": 5}]
assert data["html"] == "<body>page</body>"
assert data["screenshot"] == "cG5n" # base64(b"png")