chore: добавлена возможность передавать локатор для выбора элемента сигнализирующего о странице антибот защиты
This commit is contained in:
1 parent
6124c604d9
commit
ce68d2727c
7 files changed
+36
-11
No files matched your search
+5
-1
@@ -26,6 +26,7 @@ class ChallengeInfo:
|
|||||||
provider: str # "cloudflare_turnstile", "datadome", "hcaptcha", "recaptcha_v2", ...
|
provider: str # "cloudflare_turnstile", "datadome", "hcaptcha", "recaptcha_v2", ...
|
||||||
success: bool = False
|
success: bool = False
|
||||||
success_locator: str | None = None # локатор на странице за защитой
|
success_locator: str | None = None # локатор на странице за защитой
|
||||||
|
detect_locator: str | None = None # локатор на странице за защитой
|
||||||
site_key: str | None = None # для стадии C, чтобы передать в 2captcha
|
site_key: str | None = None # для стадии C, чтобы передать в 2captcha
|
||||||
meta: dict | None = None # что-то специфичное для провайдера
|
meta: dict | None = None # что-то специфичное для провайдера
|
||||||
|
|
||||||
@@ -55,6 +56,7 @@ class AntiBotProvider:
|
|||||||
_solver_cls: Type[Solver]
|
_solver_cls: Type[Solver]
|
||||||
_detector_cls: Type[Detector]
|
_detector_cls: Type[Detector]
|
||||||
_success_locator: str | None = None
|
_success_locator: str | None = None
|
||||||
|
_detect_locator: str | None = None
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.detector = self._detector_cls()
|
self.detector = self._detector_cls()
|
||||||
@@ -64,6 +66,7 @@ class AntiBotProvider:
|
|||||||
stage = Stage.INTERSTITIAL,
|
stage = Stage.INTERSTITIAL,
|
||||||
provider = self.provider,
|
provider = self.provider,
|
||||||
success_locator = self._success_locator,
|
success_locator = self._success_locator,
|
||||||
|
detect_locator = self._detect_locator,
|
||||||
)
|
)
|
||||||
# обновление info
|
# обновление info
|
||||||
await self.detector.detect(page, info)
|
await self.detector.detect(page, info)
|
||||||
@@ -72,9 +75,10 @@ class AntiBotProvider:
|
|||||||
async def solve(self, page: Page, info: ChallengeInfo):
|
async def solve(self, page: Page, info: ChallengeInfo):
|
||||||
await self.solver.solve(page, info)
|
await self.solver.solve(page, info)
|
||||||
|
|
||||||
def configure(self, success_locator=None, **kwargs):
|
def configure(self, success_locator=None, detect_locator=None, **kwargs):
|
||||||
self.solver = self._solver_cls(**kwargs)
|
self.solver = self._solver_cls(**kwargs)
|
||||||
self._success_locator = success_locator
|
self._success_locator = success_locator
|
||||||
|
self._detect_locator = detect_locator
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
del self.solver
|
del self.solver
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class ReCaptchaDetector(Detector):
|
|||||||
interactive_marker_selector = "body > div:nth-child(2) > div:nth-child(4) > iframe:nth-child(1)"
|
interactive_marker_selector = "body > div:nth-child(2) > div:nth-child(4) > iframe:nth-child(1)"
|
||||||
|
|
||||||
# попытка определить что мы вообще на странице блокировки
|
# попытка определить что мы вообще на странице блокировки
|
||||||
marker_selector = "#captcha-form"
|
marker_selector = info.detect_locator or "#captcha-form"
|
||||||
if not await page.query_selector(marker_selector):
|
if not await page.query_selector(marker_selector):
|
||||||
log.debug("Page is not a challenge form")
|
log.debug("Page is not a challenge form")
|
||||||
if info.success_locator:
|
if info.success_locator:
|
||||||
|
|||||||
@@ -25,7 +25,11 @@ class ChallengeOutcome:
|
|||||||
|
|
||||||
|
|
||||||
async def pass_challenges(
|
async def pass_challenges(
|
||||||
antibot_name, page, *, captcha=None, success_locator: str | None = None, timeout_ms=120_000) -> ChallengeOutcome:
|
antibot_name, page, *,
|
||||||
|
captcha=None,
|
||||||
|
success_locator: str | None = None,
|
||||||
|
detect_locator: str | None = None,
|
||||||
|
timeout_ms=120_000) -> ChallengeOutcome:
|
||||||
# установка дедлайна
|
# установка дедлайна
|
||||||
deadline = time.monotonic() + timeout_ms / 1000
|
deadline = time.monotonic() + timeout_ms / 1000
|
||||||
|
|
||||||
@@ -36,7 +40,11 @@ async def pass_challenges(
|
|||||||
else:
|
else:
|
||||||
captcha_solver = None
|
captcha_solver = None
|
||||||
provider = await select_one(
|
provider = await select_one(
|
||||||
page, antibot_name, captcha_solver=captcha_solver, success_locator=success_locator)
|
page, antibot_name,
|
||||||
|
captcha_solver=captcha_solver,
|
||||||
|
success_locator=success_locator,
|
||||||
|
detect_locator=detect_locator,
|
||||||
|
)
|
||||||
except ProviderNotDetected:
|
except ProviderNotDetected:
|
||||||
return ChallengeOutcome(False, None, None, "Provider not detected")
|
return ChallengeOutcome(False, None, None, "Provider not detected")
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
from .hcaptcha import SolverHCaptcha
|
from .hcaptcha import SolverHCaptcha
|
||||||
|
from .recaptcha import SolverReCaptcha
|
||||||
from .base import load_captcha
|
from .base import load_captcha
|
||||||
+15
-6
@@ -65,28 +65,37 @@ async def wait_for(page: Page, act: ActionRequest, **kwargs) -> str | None:
|
|||||||
|
|
||||||
|
|
||||||
@register
|
@register
|
||||||
async def pass_challenge(page: Page, act: ActionRequest, *, antibot_name, success_locator = None, captcha_key= None, **kwargs) -> str | None:
|
async def pass_challenge(
|
||||||
assert act.selector
|
page: Page, act: ActionRequest, *,
|
||||||
|
antibot_name, success_locator=None, captcha_key=None, detect_locator=None,
|
||||||
|
**kwargs
|
||||||
|
) -> str | None:
|
||||||
await pass_challenges(
|
await pass_challenges(
|
||||||
antibot_name, page,
|
antibot_name, page,
|
||||||
captcha=captcha_key, success_locator=act.selector
|
captcha=captcha_key,
|
||||||
|
success_locator=act.selector or success_locator,
|
||||||
|
detect_locator=detect_locator
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def execute(
|
async def execute(
|
||||||
page: Page, actions: list[ActionRequest],
|
page: Page, actions: list[ActionRequest],
|
||||||
captcha_key: str | None = None, antibot_name: str | None = None,
|
captcha_key: str | None = None, antibot_name: str | None = None,
|
||||||
success_locator: str | None = None) -> list[dict]:
|
success_locator: str | None = None,
|
||||||
|
detect_locator: str | None = None) -> list[dict]:
|
||||||
"""Выполнение очереди автоматизации"""
|
"""Выполнение очереди автоматизации"""
|
||||||
actions_result = []
|
actions_result = []
|
||||||
ctx = {
|
ctx = {
|
||||||
"captcha_key": captcha_key,
|
"captcha_key": captcha_key,
|
||||||
"antibot_name": antibot_name,
|
"antibot_name": antibot_name,
|
||||||
"success_locator": success_locator
|
"success_locator": success_locator,
|
||||||
|
"detect_locator": detect_locator,
|
||||||
}
|
}
|
||||||
await pass_challenges(
|
await pass_challenges(
|
||||||
antibot_name, page,
|
antibot_name, page,
|
||||||
captcha=captcha, success_locator=success_locator
|
captcha=captcha_key,
|
||||||
|
success_locator=success_locator,
|
||||||
|
detect_locator=detect_locator,
|
||||||
)
|
)
|
||||||
for act in actions:
|
for act in actions:
|
||||||
new_line = {
|
new_line = {
|
||||||
|
|||||||
@@ -32,5 +32,6 @@ class SolveRequest(BaseModel):
|
|||||||
# TODO: screenshot: bool = False
|
# TODO: screenshot: bool = False
|
||||||
|
|
||||||
captcha: str | None = None
|
captcha: str | None = None
|
||||||
|
captcha_detect_locator: str | None = None
|
||||||
captcha_success_locator: str | None = None
|
captcha_success_locator: str | None = None
|
||||||
captcha_type: str | None = None
|
captcha_type: str | None = None
|
||||||
+3
-1
@@ -130,7 +130,9 @@ async def solve(
|
|||||||
|
|
||||||
actions_result = await actions.execute(
|
actions_result = await actions.execute(
|
||||||
page, payload.actions, payload.captcha,
|
page, payload.actions, payload.captcha,
|
||||||
antibot_name=payload.captcha_type, success_locator=payload.captcha_success_locator
|
antibot_name=payload.captcha_type,
|
||||||
|
success_locator=payload.captcha_success_locator,
|
||||||
|
detect_locator=payload.captcha_detect_locator,
|
||||||
)
|
)
|
||||||
|
|
||||||
status = not "error" in actions_result[-1]
|
status = not "error" in actions_result[-1]
|
||||||
|
|||||||
Reference in new issue
Block a user