diff --git a/core/douyu/login.py b/core/douyu/login.py index c6e72a6..e824da0 100644 --- a/core/douyu/login.py +++ b/core/douyu/login.py @@ -72,7 +72,7 @@ class DouyuLogin: proxy_api_url: Optional[str] = None, timeout: tuple[float, float] = REQUEST_TIMEOUT, max_geetest_retries: int = 5, - max_proxy_retries: int = 10, + max_proxy_retries: int = 0, max_login_retries: int = 3, max_total_time: float = 300, whitelist_uid: str = "", @@ -328,6 +328,7 @@ class DouyuLogin: """ logger.info(f"开始登录账号: {self.account.username}") start_time = time.monotonic() + deadline = start_time + self.max_total_time for attempt in range(1, self.max_login_retries + 1): elapsed = time.monotonic() - start_time @@ -347,7 +348,7 @@ class DouyuLogin: # 2️⃣ 极验 fullpage 验证 logger.info("步骤2: 极验 fullpage 验证...") - validate, seccode = self._solve_geetest(gt, challenge) + validate, seccode = self._solve_geetest(gt, challenge, deadline=deadline) # 3️⃣ 第二次登录(带极验) logger.info("步骤3: 第二次登录(带极验验证)...") @@ -454,7 +455,7 @@ class DouyuLogin: return gt, challenge, code_token, self.session.cookies.get_dict() - def _solve_geetest(self, gt: str, challenge: str) -> Tuple[str, str]: + def _solve_geetest(self, gt: str, challenge: str, deadline: float = 0) -> Tuple[str, str]: """ 解决极验 fullpage 验证(带重试机制) @@ -465,6 +466,8 @@ class DouyuLogin: Args: gt: 极验gt参数 challenge: 极验challenge参数(第一次登录返回的) + deadline: 登录整体超时截止时间(monotonic),0=不限 + challenge: 极验challenge参数(第一次登录返回的) Returns: (validate, seccode) @@ -479,6 +482,10 @@ class DouyuLogin: _SOFT_FAIL_THRESHOLD = 2 # 同一代理连续临时失败2次才换 for attempt in range(max_attempts): + # 超时兜底:极验验证不应超过登录整体时间上限 + if deadline and time.monotonic() > deadline: + raise ValueError(f"极验验证超时(登录整体时间耗尽)") + try: if self.max_proxy_retries > 0: logger.info(f"极验验证尝试 {attempt + 1}/{max_attempts}") diff --git a/web/backend/schemas.py b/web/backend/schemas.py index 2fa585a..ffe57c8 100644 --- a/web/backend/schemas.py +++ b/web/backend/schemas.py @@ -125,7 +125,7 @@ class AccountOut(BaseModel): class LoginBatchRequest(BaseModel): account_ids: list[int] max_geetest_retries: int = 5 - max_proxy_retries: int = 10 # 代理切换次数,0=无限切换直到成功 + max_proxy_retries: int = 0 # 代理切换次数,0=无限切换直到成功 max_login_retries: int = 3 # 登录整体重试次数(换代理从头重跑) max_total_time: float = 300 # 单账号登录总时长上限(秒),超时则放弃 concurrency: int = 3 # 并发数,1-10 diff --git a/web/backend/services/login_service.py b/web/backend/services/login_service.py index b73cf8f..f8ceb90 100644 --- a/web/backend/services/login_service.py +++ b/web/backend/services/login_service.py @@ -29,7 +29,7 @@ class LoginBatchRunner: created_by: int, creator_permissions: list[str], max_geetest_retries: int = 5, - max_proxy_retries: int = 10, + max_proxy_retries: int = 0, max_login_retries: int = 3, max_total_time: float = 300, proxy_config: Optional[ProxyConfigModel] = None, diff --git a/web/frontend/src/pages/LoginTasksPage.tsx b/web/frontend/src/pages/LoginTasksPage.tsx index 9616b77..3e7f79d 100644 --- a/web/frontend/src/pages/LoginTasksPage.tsx +++ b/web/frontend/src/pages/LoginTasksPage.tsx @@ -44,7 +44,7 @@ export default function LoginTasksPage() { }); const [maxProxyRetries, setMaxProxyRetries] = useState(() => { const v = localStorage.getItem('login_max_proxy_retries'); - return v ? Math.max(0, Number(v) || 10) : 10; + return v ? Math.max(0, Number(v) || 0) : 0; }); // 值变化时自动持久化