
在大规模数据采集中,单个代理 IP 很容易因请求频率过高而被目标网站限制。本文介绍如何用 Python 构建一个轻量级代理池,实现自动健康检查、IP 轮换和故障转移,并提供完整的代码示例。
数据采集任务中,如果只使用一两个固定的代理出口,会遇到以下问题:
一个高可用的代理池应当具备:自动获取代理、健康检查、动态轮换、失败重试等能力。
使用 Python 内置的 queue.Queue 或 Redis 列表来存储代理地址。为了演示方便,本示例使用列表 + 锁的方式。
定期对代理池中的每个 IP 发送测试请求,根据响应状态码和延迟判断其可用性,剔除失效节点。
支持随机轮换、加权轮换(根据历史成功率)等策略。
以下是一个轻量级代理池的 Python 实现,包含获取代理、健康检查、随机轮换和自动重试。
import requests
import time
import random
import threading
from queue import Queue
class ProxyPool:
"""轻量级代理池,支持健康检查和随机轮换"""
def __init__(self, proxy_list=None, check_interval=60):
self.proxy_queue = Queue()
self.lock = threading.Lock()
self.healthy = set()
self.check_interval = check_interval
if proxy_list:
for proxy in proxy_list:
self.proxy_queue.put(proxy)
# 启动后台健康检查线程
self._start_health_check()
def _check_proxy(self, proxy, test_url="http://httpbin.org/ip", timeout=5):
"""检测单个代理是否可用,返回布尔值"""
try:
proxies = {"http": proxy, "https": proxy}
start = time.time()
resp = requests.get(test_url, proxies=proxies, timeout=timeout)
if resp.status_code == 200 and (time.time() - start) < 2:
return True
except:
pass
return False
def _health_check_loop(self):
"""后台定期健康检查"""
while True:
time.sleep(self.check_interval)
with self.lock:
to_check = list(self.healthy) if self.healthy else list(self.proxy_queue.queue)
for proxy in to_check:
if self._check_proxy(proxy):
with self.lock:
self.healthy.add(proxy)
else:
with self.lock:
self.healthy.discard(proxy)
# 也可以将失效代理放回队列末尾,此处简单丢弃
def _start_health_check(self):
t = threading.Thread(target=self._health_check_loop, daemon=True)
t.start()
def get_proxy(self, strategy="random"):
"""获取一个可用代理,支持 random 策略"""
with self.lock:
if strategy == "random":
if self.healthy:
return random.choice(list(self.healthy))
elif not self.proxy_queue.empty():
# 队列中还有未检测的代理,取出一个并检测
proxy = self.proxy_queue.get()
if self._check_proxy(proxy):
self.healthy.add(proxy)
return proxy
return None
def fetch_with_proxy_pool(url, proxy_pool, max_retries=3):
"""使用代理池发送请求,失败自动重试"""
for attempt in range(max_retries):
proxy = proxy_pool.get_proxy()
if not proxy:
time.sleep(2)
continue
try:
proxies = {"http": proxy, "https": proxy}
resp = requests.get(url, proxies=proxies, timeout=10)
if resp.status_code == 200:
return resp.text
except Exception:
pass
time.sleep(random.uniform(1, 3))
raise Exception("All proxies failed")
# 示例用法:以某住宅代理服务商(例如辣椒HTTP)提供的代理列表作为初始池
# 实际使用时请替换为真实代理地址(示例地址仅作演示,具体接入方式参考官方文档:https://www.lajiaohttp.com?kwd=hyj-csdn)
proxy_list = [
"http://user:pass@proxy1.example.com:8080",
"http://user:pass@proxy2.example.com:8080",
# 更多代理...
]
pool = ProxyPool(proxy_list)
result = fetch_with_proxy_pool("https://httpbin.org/ip", pool)
print(result)aiohttp + asyncio 配合代理池。curl_cffi 等库模拟浏览器 TLS 指纹,提高成功率。本文实现了一个基础的代理池,可以自动检查代理可用性并进行轮换。在实际项目中,你可以将此代理池集成到采集框架中,大幅提升采集的稳定性和效率。如果希望使用高质量的住宅代理资源,可参考示例中的服务商文档获取接入方式。
以上代码基于 Python 3.8+ 测试,可根据实际需求调整参数。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。