修复并发账号分配到同一个代理的问题
问题:get_proxy每次返回池中第一个代理,导致并发账号用同一个代理, 容易触发斗鱼/极验风控。 修复: - 增加_in_use集合,get_proxy取代理时标记为使用中,避免重复分配 - 代理池空但所有代理都在使用中时,允许复用(兜底) - 新增release_proxy方法,登录完成后归还代理到池 - login.py的finally块中调用release_proxy,确保成功/失败都归还 - mark_bad同时从_in_use移除
This commit is contained in:
+18
-2
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user