feature!: перенимаем реализацию прохождения cf_turnstile у scrapling

https://github.com/D4Vinci/Scrapling

BREAKING_CHANGES: клик отрабатывает, но прохода не случается
This commit is contained in:
protokey committed 2026-09-23 11:21:18 +04:00
1 parent f2d4d441f4
commit 8f7645b2b9
11 files changed
+193 -30

No files matched your search

+2 -2
View File
@@ -11,8 +11,8 @@ from dataclasses import dataclass
from enum import Enum
from typing import Type
from playwright.async_api import Page
from playwright.async_api import TimeoutError as PWTimeoutError
from patchright.async_api import Page
from patchright.async_api import TimeoutError as PWTimeoutError
async def click_and_race(page, element, challenge_locator, timeout=30_000):
+6 -3
View File
@@ -10,8 +10,8 @@ import random
import string
from typing import Optional
from playwright.async_api import TimeoutError
from playwright.async_api import Page
from patchright.async_api import TimeoutError
from patchright.async_api import Page
# последняя известная позиция курсора на страницу — Playwright не даёт её прочитать из браузера,
# поэтому считаем сами, чтобы следующее движение начиналось не из (0, 0), а оттуда, где реально
@@ -103,11 +103,14 @@ async def click_human(
"""move_mouse_human + клик с человеческой задержкой между наведением и down/up, вместо
мгновенного page.mouse.click(x, y)."""
await move_mouse_human(page, x, y, **move_kwargs)
print('wait for timeout')
await page.wait_for_timeout(random.uniform(50, 180))
print('key down')
await page.mouse.down(button=button)
print('sleep')
await page.wait_for_timeout(random.uniform(40, 99))
print('key up')
await page.mouse.up(button=button)
await move_mouse_human(page, x-50, y+50, **move_kwargs)
async def wait_for_networkidle(page: Page, timeout: Optional[int] = None):
+4 -4
View File
@@ -63,7 +63,7 @@ import re
import time
from random import randint
from playwright.async_api import Page
from patchright.async_api import Page
from ..base import Detector, ChallengeInfo, AntiBotProvider, Solver
from ..base import Stage
@@ -140,9 +140,10 @@ __CF_PATTERN__ = re.compile(r"^https://challenges\.cloudflare\.com/cdn-cgi/chall
class CloudflareSolver(Solver):
async def solve(self, page: Page, info: ChallengeInfo):
print("start solving")
iframe = page.frame(url=__CF_PATTERN__)
if iframe:
await page.wait_for_timeout(randint(4000, 7000)) # дать чекбоксу домонтироваться в closed shadow root
await page.wait_for_timeout(randint(500, 1000))
frame_el = await iframe.frame_element()
box = await frame_el.bounding_box()
else:
@@ -152,8 +153,6 @@ class CloudflareSolver(Solver):
# # Calculate the Captcha coordinates for any viewport
captcha_x, captcha_y = box["x"] + randint(26, 28), box["y"] + randint(25, 27)
# await page.mouse.click(captcha_x, captcha_y, delay=randint(100, 200), button="left")
await click_human(page, captcha_x, captcha_y)
await wait_for_networkidle(page)
@@ -186,6 +185,7 @@ class CloudflareSolver(Solver):
return
return
else:
captcha_solver = self._opt.get("captcha_solver")
if not captcha_solver:
raise RuntimeError("Нужен captcha_solver (2captcha) чтобы решить Turnstile")
+1 -1
View File
@@ -1,7 +1,7 @@
import json
import logging
from playwright.async_api import Page
from patchright.async_api import Page
from captcha.base import Captcha
+1 -1
View File
@@ -1,7 +1,7 @@
"""
реестр детекторов, порядок проверки
"""
from playwright.async_api import Page
from patchright.async_api import Page
from .base import AntiBotProvider
from .exceptions import ProviderNotDetected