fix: reCAPTCHA — закрытие окна с картинками и вызов callback (#10)
- Окно с картинками закрывается кликом в угол подложки: в её центре лежит само окно и перехватывает клик (Locator.click падал по таймауту 60 с). - form_submit выполняется в основном мире страницы (isolated_context=False): префикс "mw:" patchright не поддерживает, в изолированном мире ___grecaptcha_cfg не виден — "Recaptcha callback function not found". - Воркер: LOG_LEVEL выставляется корневому логгеру явно — dramatiq настраивает логирование раньше, и basicConfig ничего не делал. make dev — LOG_LEVEL=DEBUG. - test_main.http: запрос на zennolab с проверкой результата по #main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4d90dc4a21
commit
0e10fb671d
5 files changed
+19
-13
No files matched your search
@@ -1,4 +1,3 @@
|
||||
import json
|
||||
import logging
|
||||
|
||||
from patchright.async_api import Page
|
||||
@@ -6,7 +5,7 @@ from patchright.async_api import Page
|
||||
from captcha.base import Captcha
|
||||
|
||||
from ..base import Detector, ChallengeInfo, Solver, AntiBotProvider, click_and_race
|
||||
from ..base import Stage
|
||||
from ..base import Stage, PWTimeoutError
|
||||
from ..registry import register
|
||||
from ..exceptions import IframeLoadError
|
||||
|
||||
@@ -56,8 +55,8 @@ class ReCaptchaSolver(Solver):
|
||||
self.captcha_solver: Captcha = self._opt["captcha_solver"]
|
||||
|
||||
async def form_submit(self, token: str) -> bool:
|
||||
# noinspection UnnecessaryLabelJS
|
||||
return await self.page.evaluate(f"mw:({JS_CHALLENGE_SUBMIT})({json.dumps(token)})")
|
||||
# ___grecaptcha_cfg живёт в основном мире страницы, а patchright по умолчанию выполняет скрипт в изолированном
|
||||
return await self.page.evaluate(JS_CHALLENGE_SUBMIT, token, isolated_context=False)
|
||||
|
||||
async def solve(self, page: Page, info: ChallengeInfo):
|
||||
self.page = page
|
||||
@@ -76,9 +75,15 @@ class ReCaptchaSolver(Solver):
|
||||
return
|
||||
else:
|
||||
log.debug("Нужно решать капчу. Закрою окошко с картинками.")
|
||||
# полупрозрачная подложка на весь экран (position: fixed), клик по ней закрывает окно. В её центре лежит
|
||||
# само окно с картинками и перехватывает клик — поэтому кликаем в угол
|
||||
element = page.locator("xpath=//div[@class='g-recaptcha-bubble-arrow']/../div[1]")
|
||||
if await element.is_visible():
|
||||
await element.click()
|
||||
try:
|
||||
await element.click(position={"x": 1, "y": 1}, timeout=5_000)
|
||||
except PWTimeoutError:
|
||||
# не закрылось — не страшно, токен уходит через callback
|
||||
log.debug("Окошко с картинками закрыть не удалось")
|
||||
|
||||
log.debug("Решаем капчу...")
|
||||
assert info.detect_locator
|
||||
|
||||
@@ -30,6 +30,7 @@ class Captcha:
|
||||
return resp
|
||||
|
||||
async def turnstile(self, url, site_key):
|
||||
# TODO: not finished!
|
||||
resp = await self._run(self._solver.turnstile, site_key, url)
|
||||
return resp
|
||||
|
||||
|
||||
@@ -10,10 +10,13 @@ import logging
|
||||
import os
|
||||
import socket
|
||||
|
||||
LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO").upper()
|
||||
logging.basicConfig(
|
||||
level=os.getenv("LOG_LEVEL", "INFO").upper(),
|
||||
level=LOG_LEVEL,
|
||||
format="%(asctime)s %(levelname)s %(name)s: %(message)s",
|
||||
)
|
||||
# под dramatiq логирование уже настроено им самим (уровень INFO) и basicConfig ничего не делает — уровень явно
|
||||
logging.getLogger().setLevel(LOG_LEVEL)
|
||||
|
||||
import dramatiq # noqa: E402
|
||||
from dramatiq.asyncio import get_event_loop_thread # noqa: E402
|
||||
|
||||
Reference in new issue
Block a user