feat: Enhance proxy testing to return detailed results including latency and errors, and display a comprehensive, formatted report in the Telegram bot.
This commit is contained in:
@@ -127,7 +127,7 @@ def save_proxies(proxies: list[str]):
|
||||
print(f"[ProxyPool] 保存代理文件失败: {e}")
|
||||
|
||||
|
||||
def test_single_proxy(proxy_url: str, timeout: int = TEST_TIMEOUT) -> bool:
|
||||
def test_single_proxy(proxy_url: str, timeout: int = TEST_TIMEOUT) -> dict:
|
||||
"""测试单个代理是否可用
|
||||
|
||||
Args:
|
||||
@@ -135,13 +135,13 @@ def test_single_proxy(proxy_url: str, timeout: int = TEST_TIMEOUT) -> bool:
|
||||
timeout: 超时秒数
|
||||
|
||||
Returns:
|
||||
bool: 代理是否可用
|
||||
dict: {"proxy": str, "alive": bool, "latency_ms": int, "error": str}
|
||||
"""
|
||||
proxies_dict = {"http": proxy_url, "https": proxy_url}
|
||||
start = time.time()
|
||||
|
||||
try:
|
||||
if CURL_AVAILABLE:
|
||||
# 使用 curl_cffi (更好的指纹)
|
||||
resp = curl_requests.head(
|
||||
TEST_URL,
|
||||
proxies=proxies_dict,
|
||||
@@ -150,17 +150,18 @@ def test_single_proxy(proxy_url: str, timeout: int = TEST_TIMEOUT) -> bool:
|
||||
impersonate="edge",
|
||||
)
|
||||
else:
|
||||
# 回退到 requests
|
||||
resp = requests.head(
|
||||
TEST_URL,
|
||||
proxies=proxies_dict,
|
||||
timeout=timeout,
|
||||
verify=False,
|
||||
)
|
||||
# 任何响应都算成功 (包括 401/403,说明代理本身是通的)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
latency = int((time.time() - start) * 1000)
|
||||
return {"proxy": proxy_url, "alive": True, "latency_ms": latency, "error": ""}
|
||||
except Exception as e:
|
||||
latency = int((time.time() - start) * 1000)
|
||||
err_msg = str(e)[:50]
|
||||
return {"proxy": proxy_url, "alive": False, "latency_ms": latency, "error": err_msg}
|
||||
|
||||
|
||||
class ProxyPool:
|
||||
@@ -192,12 +193,12 @@ class ProxyPool:
|
||||
timeout: 单个代理超时秒数
|
||||
|
||||
Returns:
|
||||
dict: {"total": int, "alive": int, "removed": int, "duration": float}
|
||||
dict: {"total": int, "alive": int, "removed": int, "duration": float, "details": list}
|
||||
"""
|
||||
# 先从文件加载最新
|
||||
all_proxies = load_proxies()
|
||||
if not all_proxies:
|
||||
self._last_test_results = {"total": 0, "alive": 0, "removed": 0, "duration": 0}
|
||||
self._last_test_results = {"total": 0, "alive": 0, "removed": 0, "duration": 0, "details": []}
|
||||
return self._last_test_results
|
||||
|
||||
total = len(all_proxies)
|
||||
@@ -205,7 +206,7 @@ class ProxyPool:
|
||||
|
||||
# 并发测试
|
||||
alive_proxies = []
|
||||
dead_proxies = []
|
||||
details = [] # 每个代理的详细结果
|
||||
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=concurrency) as executor:
|
||||
future_to_proxy = {
|
||||
@@ -216,31 +217,37 @@ class ProxyPool:
|
||||
for future in concurrent.futures.as_completed(future_to_proxy):
|
||||
proxy = future_to_proxy[future]
|
||||
try:
|
||||
is_alive = future.result()
|
||||
if is_alive:
|
||||
result = future.result()
|
||||
details.append(result)
|
||||
if result["alive"]:
|
||||
alive_proxies.append(proxy)
|
||||
else:
|
||||
dead_proxies.append(proxy)
|
||||
except Exception:
|
||||
dead_proxies.append(proxy)
|
||||
except Exception as e:
|
||||
details.append({"proxy": proxy, "alive": False, "latency_ms": 0, "error": str(e)[:50]})
|
||||
|
||||
# 按原始顺序排序 details
|
||||
proxy_order = {p: i for i, p in enumerate(all_proxies)}
|
||||
details.sort(key=lambda d: proxy_order.get(d["proxy"], 999))
|
||||
|
||||
duration = time.time() - start_time
|
||||
|
||||
# 更新工作代理池
|
||||
# 更新工作代理池 (保持原始顺序)
|
||||
ordered_alive = [p for p in all_proxies if p in set(alive_proxies)]
|
||||
with self._lock:
|
||||
self._working_proxies = alive_proxies
|
||||
self._working_proxies = ordered_alive
|
||||
self._index = 0
|
||||
|
||||
# 保存存活的代理到文件 (移除死亡代理)
|
||||
if dead_proxies:
|
||||
save_proxies(alive_proxies)
|
||||
# 保存存活的代理到文件
|
||||
dead_count = total - len(ordered_alive)
|
||||
if dead_count > 0:
|
||||
save_proxies(ordered_alive)
|
||||
|
||||
self._last_test_time = time.time()
|
||||
self._last_test_results = {
|
||||
"total": total,
|
||||
"alive": len(alive_proxies),
|
||||
"removed": len(dead_proxies),
|
||||
"alive": len(ordered_alive),
|
||||
"removed": dead_count,
|
||||
"duration": round(duration, 1),
|
||||
"details": details,
|
||||
}
|
||||
|
||||
return self._last_test_results
|
||||
|
||||
Reference in New Issue
Block a user