feat: 添加 CapSolver 处理 Cloudflare Turnstile 的功能

This commit is contained in:
晓丰 2025-06-04 21:35:01 +08:00
parent e79be58ac0
commit 52e2139ff4

View File

@ -8,13 +8,14 @@ from playwright.sync_api import (
Browser, Browser,
) )
def solve_turnstile_capsolver(page: Page, def solve_turnstile_capsolver(page: Page,
timeout: int = 120) -> bool: timeout: int = 120) -> bool:
""" """
使用 CapSolver 自动完成当前 Page 上的 Cloudflare Turnstile 使用 CapSolver 自动完成当前 Page 上的 Cloudflare Turnstile
成功返回 True失败/超时返回 False 成功返回 True失败/超时返回 False
""" """
cap_key="CAP-A76C932D4C6CCB3CA748F77FDC07D996" cap_key = "CAP-A76C932D4C6CCB3CA748F77FDC07D996"
widget = page.query_selector("div.cf-turnstile[data-sitekey]") widget = page.query_selector("div.cf-turnstile[data-sitekey]")
if not widget: if not widget:
return False return False
@ -38,7 +39,6 @@ def solve_turnstile_capsolver(page: Page,
return False return False
task_id = create_resp["taskId"] task_id = create_resp["taskId"]
poll_payload = {"clientKey": cap_key, "taskId": task_id} poll_payload = {"clientKey": cap_key, "taskId": task_id}
token = None token = None
elapsed, step = 0, 3 elapsed, step = 0, 3
@ -60,7 +60,6 @@ def solve_turnstile_capsolver(page: Page,
print("[CapSolver] 超时未取到 token") print("[CapSolver] 超时未取到 token")
return False return False
page.evaluate( page.evaluate(
"""(tk) => { """(tk) => {
const ta = document.querySelector('textarea[name="cf-turnstile-response"]'); const ta = document.querySelector('textarea[name="cf-turnstile-response"]');
@ -72,6 +71,8 @@ def solve_turnstile_capsolver(page: Page,
) )
page.wait_for_timeout(1500) page.wait_for_timeout(1500)
return True return True
def require_login(func): def require_login(func):
@functools.wraps(func) @functools.wraps(func)
def wrapper(self, *args, **kwargs): def wrapper(self, *args, **kwargs):
@ -107,6 +108,11 @@ class DailymotionClient:
self.page.goto(self.url, timeout=30000) self.page.goto(self.url, timeout=30000)
self.page.wait_for_load_state("networkidle", timeout=30000) self.page.wait_for_load_state("networkidle", timeout=30000)
if self.page.query_selector("div.cf-turnstile[data-sitekey]"):
ok = solve_turnstile_capsolver(self.page)
if not ok:
raise RuntimeError("CapSolver 处理 Turnstile 失败")
logbtn = self.page.locator("//a[@class='login button']") logbtn = self.page.locator("//a[@class='login button']")
if logbtn.count() > 0: if logbtn.count() > 0:
logbtn.nth(0).click() logbtn.nth(0).click()
@ -148,12 +154,10 @@ class DailymotionClient:
return self.page.locator("//a[@class='login button']").count() == 0 return self.page.locator("//a[@class='login button']").count() == 0
def is_logged_in(self) -> bool: def is_logged_in(self) -> bool:
"""带本地缓存,避免每几秒都访问一次页面。"""
now = time.time() now = time.time()
if now - self._last_check_ts < self.check_interval: if now - self._last_check_ts < self.check_interval:
return self._last_check_result return self._last_check_result
# 重新检测
try: try:
ok = self._detect_login() ok = self._detect_login()
except Exception: except Exception:
@ -173,6 +177,10 @@ class DailymotionClient:
1) please help remove these videos 1) please help remove these videos
2) The drama series titles are {} 2) The drama series titles are {}
""".format(title) """.format(title)
if self.page.query_selector("div.cf-turnstile[data-sitekey]"):
ok = solve_turnstile_capsolver(self.page)
if not ok:
raise RuntimeError("CapSolver 处理 Turnstile 失败")
file_path = f'screenshots/{str(int(time.time()))}_{title}_{link.split("/")[-1]}.png' file_path = f'screenshots/{str(int(time.time()))}_{title}_{link.split("/")[-1]}.png'
self.page.screenshot(path=file_path) self.page.screenshot(path=file_path)
resports = self.page.locator('li.blocks-item:nth-child(8)') resports = self.page.locator('li.blocks-item:nth-child(8)')