chore: настройка определения что мы на странице cf_turnstile
This commit is contained in:
1 parent
257310b7d5
commit
405e5ed2d0
1 file changed
+55
-4
@@ -84,7 +84,7 @@ class CloudflareDetector(Detector):
|
|||||||
|
|
||||||
async def detect(self, page: Page, info: ChallengeInfo):
|
async def detect(self, page: Page, info: ChallengeInfo):
|
||||||
log.debug("CloudflareDetector run")
|
log.debug("CloudflareDetector run")
|
||||||
await wait_for_networkidle(page)
|
await wait_for_page_stability(page, True, False)
|
||||||
|
|
||||||
log.debug("Страница загружена полностью")
|
log.debug("Страница загружена полностью")
|
||||||
info.meta = {}
|
info.meta = {}
|
||||||
@@ -94,7 +94,9 @@ class CloudflareDetector(Detector):
|
|||||||
|
|
||||||
log.debug(f"ищем {marker_selector} успех если есть {info.success_locator}")
|
log.debug(f"ищем {marker_selector} успех если есть {info.success_locator}")
|
||||||
|
|
||||||
if not await page.query_selector(marker_selector):
|
cf_type = await self._detect_cloudflare(page)
|
||||||
|
|
||||||
|
if not cf_type:
|
||||||
log.debug("на странице нет маркера преграды")
|
log.debug("на странице нет маркера преграды")
|
||||||
if info.success_locator:
|
if info.success_locator:
|
||||||
info.success = bool(await page.query_selector(info.success_locator))
|
info.success = bool(await page.query_selector(info.success_locator))
|
||||||
@@ -108,8 +110,6 @@ class CloudflareDetector(Detector):
|
|||||||
log.debug("Решение не требуется")
|
log.debug("Решение не требуется")
|
||||||
return
|
return
|
||||||
|
|
||||||
content = await page.content()
|
|
||||||
cf_type = next((t for t in self._CTYPES if f"cType: '{t}'" in content), None)
|
|
||||||
info.meta["cf_type"] = cf_type
|
info.meta["cf_type"] = cf_type
|
||||||
log.debug(f"cType со страницы: {cf_type!r}")
|
log.debug(f"cType со страницы: {cf_type!r}")
|
||||||
|
|
||||||
@@ -134,6 +134,41 @@ class CloudflareDetector(Detector):
|
|||||||
else:
|
else:
|
||||||
info.stage = Stage.INTERSTITIAL
|
info.stage = Stage.INTERSTITIAL
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def _detect_cloudflare(page: Page) -> str | None:
|
||||||
|
"""
|
||||||
|
Detect the type of Cloudflare challenge present in the provided page content.
|
||||||
|
|
||||||
|
This function analyzes the given page content to identify whether a specific
|
||||||
|
type of Cloudflare challenge is present. It checks for three predefined
|
||||||
|
challenge types: non-interactive, managed, and interactive. If a challenge
|
||||||
|
type is detected, it returns the corresponding type as a string. If no
|
||||||
|
challenge type is detected, it returns None.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
page_content (str): The content of the page to analyze for Cloudflare
|
||||||
|
challenge types.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: A string representing the detected Cloudflare challenge type, if
|
||||||
|
found. Returns None if no challenge matches.
|
||||||
|
"""
|
||||||
|
challenge_types = (
|
||||||
|
"non-interactive",
|
||||||
|
"managed",
|
||||||
|
"interactive",
|
||||||
|
)
|
||||||
|
page_content = await page.content()
|
||||||
|
for ctype in challenge_types:
|
||||||
|
if f"cType: '{ctype}'" in page_content:
|
||||||
|
return ctype
|
||||||
|
|
||||||
|
# Check if turnstile captcha is embedded inside the page (Usually inside a closed Shadow iframe)
|
||||||
|
if await page.query_selector('script[src*="challenges.cloudflare.com/turnstile/v"]'):
|
||||||
|
return "embedded"
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
__CF_PATTERN__ = re.compile(r"^https://challenges\.cloudflare\.com/cdn-cgi/challenge-platform/.*")
|
__CF_PATTERN__ = re.compile(r"^https://challenges\.cloudflare\.com/cdn-cgi/challenge-platform/.*")
|
||||||
|
|
||||||
@@ -170,6 +205,7 @@ class CloudflareSolver(Solver):
|
|||||||
while time.time() < deadline:
|
while time.time() < deadline:
|
||||||
if not await page.query_selector(info.detect_locator):
|
if not await page.query_selector(info.detect_locator):
|
||||||
return
|
return
|
||||||
|
await page.wait_for_timeout(1)
|
||||||
return
|
return
|
||||||
elif info.stage == Stage.INTERSTITIAL:
|
elif info.stage == Stage.INTERSTITIAL:
|
||||||
if info.success_locator:
|
if info.success_locator:
|
||||||
@@ -184,6 +220,7 @@ class CloudflareSolver(Solver):
|
|||||||
while time.time() < deadline:
|
while time.time() < deadline:
|
||||||
if not await page.query_selector(info.detect_locator):
|
if not await page.query_selector(info.detect_locator):
|
||||||
return
|
return
|
||||||
|
await page.wait_for_timeout(1)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
|
|
||||||
@@ -193,6 +230,20 @@ class CloudflareSolver(Solver):
|
|||||||
await captcha_solver.solve(info.meta["container_selector"], page)
|
await captcha_solver.solve(info.meta["container_selector"], page)
|
||||||
# TODO: возбудить js
|
# TODO: возбудить js
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _challenge_cleared(cls, page_content: str, challenge_type: str) -> bool:
|
||||||
|
"""
|
||||||
|
Check whether the Cloudflare challenge is no longer present in the page content.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
page_content (str): The content of the page to analyze.
|
||||||
|
challenge_type (str): The challenge type returned by `_detect_cloudflare`.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if the challenge is gone from the page, False otherwise.
|
||||||
|
"""
|
||||||
|
return challenge_type == "embedded" or cls._detect_cloudflare(page_content) is None
|
||||||
|
|
||||||
|
|
||||||
@register
|
@register
|
||||||
class ReCaptchaProvider(AntiBotProvider):
|
class ReCaptchaProvider(AntiBotProvider):
|
||||||
|
|||||||
Reference in new issue
Block a user