diff --git a/src/engine/__init__.py b/src/engine/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/engine/actions.py b/src/engine/actions.py new file mode 100644 index 0000000..f09be90 --- /dev/null +++ b/src/engine/actions.py @@ -0,0 +1,47 @@ +from playwright.async_api import Page + +from engine.schemas import ActionRequest + +_actions: dict = {} + + +def register(fun) -> None: + _actions[fun.__name__] = fun + return fun + + +@register +async def fill(page: Page, act: ActionRequest) -> str | None: + ... + + +@register +async def mouse_move(page: Page, act: ActionRequest) -> str | None: + ... + + +@register +async def click(page: Page, act: ActionRequest) -> str | None: + ... + + +@register +async def wait_for(page: Page, act: ActionRequest) -> str | None: + try: + assert act.selector + await page.wait_for_selector(act.selector, timeout=act.timeout * 1000) + except Exception as e: + return str(e) + else: + return None + + +async def execute(page: Page, actions: list[ActionRequest]) -> list[str]: + actions_result = [] + for act in actions: + try: + await _actions[act.type](page, act) + except Exception as e: + actions_result.append({"type": act.type, "ok": "false", "error": str(e)}) + break + return actions_result diff --git a/src/engine/schemas.py b/src/engine/schemas.py new file mode 100644 index 0000000..84b2771 --- /dev/null +++ b/src/engine/schemas.py @@ -0,0 +1,17 @@ +from pydantic import BaseModel + + +class ActionRequest(BaseModel): + type: str + selector: str | None = None + value: str | None = None + timeout: int | None = None + + +class SolveRequest(BaseModel): + url: str + proxy: str + actions: list[ActionRequest] + timeout: int | None = None + screen: str = "1280x720" + user_agent: str | None = None diff --git a/src/main.py b/src/main.py index be15578..3f15c3a 100644 --- a/src/main.py +++ b/src/main.py @@ -3,25 +3,10 @@ from datetime import datetime from camoufox.async_api import AsyncCamoufox from fastapi import FastAPI from fastapi import Request -from playwright.async_api import Page -from pydantic import BaseModel +from playwright.async_api import ViewportSize, ProxySettings - -class ActionRequest(BaseModel): - type: str - selector: str | None = None - value: str | None = None - timeout: int | None = None - - -class SolveRequest(BaseModel): - url: str - proxy: str - actions: list[ActionRequest] - timeout: int | None = None - screen: str | None = None - user_agent: str | None = None - captcha: str | None = None +from engine.schemas import SolveRequest +from engine import actions app = FastAPI() @@ -32,56 +17,27 @@ async def root(): return {"message": "Hello World"} -async def _fill(page: "Page", act: ActionRequest) -> str | None: - ... - - -async def _mouse_move(page: "Page", act: ActionRequest) -> str | None: - ... - - -async def _click(page: "Page", act: ActionRequest) -> str | None: - ... - - -async def _wait_for(page: Page, act: ActionRequest) -> str | None: - try: - assert act.selector - await page.wait_for_selector(act.selector, timeout=act.timeout * 1000) - except Exception as e: - return str(e) - else: - return None - - @app.post("/v1/solve") async def solve(request: Request, payload: SolveRequest): api_key = request.headers.get('X-API-Key') async with AsyncCamoufox() as camoufo: - page = await camoufo.new_page() + # TODO: настройка контекста + scr_w, scr_h = payload.screen.split("x") + scr_size = ViewportSize(width=int(scr_w), height=int(scr_h)) + # TODO: распарс proxy-урл и заполнение объекта + # proxy = ProxySettings(socks5://host:port, username, password) + proxy = None + page = await camoufo.new_page( + user_agent=payload.user_agent, + proxy=proxy, + viewport=scr_size, + screen=scr_size, + ) page.set_default_timeout(30_000) await page.goto(url=payload.url) - actions_result = [] - status = True - error = None - - for act in payload.actions: - result = await { - "fill": _fill, - "mouse_move": _mouse_move, - "click": _click, - "wait_for": _wait_for, - }[act.type](page, act) - if( ok := result ) is None: - act_log = {"type": act.type, "ok": ok} - else: - act_log = {"type": act.type, "ok": ok, "error": result} - actions_result.append(act_log) - if "error" in act_log: - status = False - error = act_log["error"] - break - + actions_result = await actions.execute(page, payload.actions) + status = not "error" in actions_result[-1] + error = ["Something error", None][status] cookies = await camoufo.cookies() html = await page.inner_html('html') await page.screenshot(