diff --git a/core/douyu/login.py b/core/douyu/login.py index c9e548a..700fb73 100644 --- a/core/douyu/login.py +++ b/core/douyu/login.py @@ -313,6 +313,10 @@ class DouyuLogin: except Exception as e: logger.error(f"登录失败: {e}") return LoginResult(success=False, message=str(e)) + finally: + # 归还代理到池,让其他账号可以复用 + if self.proxy_manager and self._current_proxy_url: + self.proxy_manager.release_proxy(self._current_proxy_url) def _first_login(self) -> Tuple[str, str, str, dict]: """ diff --git a/core/douyu/proxy.py b/core/douyu/proxy.py index e290331..40bdd69 100644 --- a/core/douyu/proxy.py +++ b/core/douyu/proxy.py @@ -20,17 +20,26 @@ class ProxyManager: self._cond = threading.Condition() # 已验证可用的代理池: {proxy_url: validated_timestamp} self._verified_pool: dict[str, float] = {} + # 正在使用中的代理(取走但未归还),避免并发账号用同一个代理 + self._in_use: set[str] = set() self._pool_ttl = 90 # 代理验证后90秒内可复用 self._fetching = False # 是否有线程正在获取代理 def _pick_from_pool_locked(self) -> Optional[str]: - """从池中取一个未过期的代理(调用前需持有锁)""" + """从池中取一个未过期且未在使用的代理(调用前需持有锁)""" now = time.time() # 清理过期代理 expired = [p for p, t in self._verified_pool.items() if now - t > self._pool_ttl] for p in expired: del self._verified_pool[p] - # 取第一个可用的 + self._in_use.discard(p) + # 取一个不在使用中的 + for proxy in self._verified_pool: + if proxy not in self._in_use: + self._in_use.add(proxy) + self.current_proxy = proxy + return proxy + # 所有代理都在使用中,但池非空(并发数>代理数),允许复用第一个 for proxy in self._verified_pool: self.current_proxy = proxy return proxy @@ -151,12 +160,19 @@ class ProxyManager: """标记代理为不可用,从池中移除(极验失败/代理连接失败时调用)""" with self._cond: removed = self._verified_pool.pop(proxy_url, None) + self._in_use.discard(proxy_url) if self.current_proxy == proxy_url: self.current_proxy = None if removed: logger.info(f"代理标记为不可用并移出池: {proxy_url} (池剩余 {len(self._verified_pool)})") self._cond.notify_all() + def release_proxy(self, proxy_url: str) -> None: + """归还代理到池(登录完成后调用,让其他账号可以复用)""" + with self._cond: + self._in_use.discard(proxy_url) + self._cond.notify_all() + def get_proxies_dict(self, proxy: str = None) -> dict: """获取requests使用的proxies字典""" proxy = proxy or self.current_proxy