共计 2372 个字符,预计需要花费 6 分钟才能阅读完成。
在上一节我们完成了一个完整的异步爬虫框架,包括任务调度、限速、重试和数据存储等核心流程。本节我们继续扩展框架能力,加入“代理池与防封策略”,让爬虫在面对高强度访问与严格反爬机制的目标站点时依然保持稳定与高效。
一、为什么需要代理池?
当你对某一站点频繁访问时,服务器通常会检测到异常流量并封锁对应 IP。代理池的作用是通过“轮换 IP + 随机使用”的策略,让服务器认为请求来自不同来源,从而提高爬虫存活率。
常见触发封禁的行为包括:
- 访问频率过高
- 请求 Header 异常
- Cookie 不稳定
- 请求来源(IP)重复且频繁
- User-Agent 固定不变
因此,代理池本质上是在流量层面“伪装”你的爬虫。
二、代理池的组成
一个完整的代理池通常包含以下部分:
-
代理来源(scraper 或付费代理服务)
- 免费代理:不稳定,需要定期检测
- 付费代理:较为稳定,适合高强度爬虫
-
代理验证器(异步验证代理可用性)
定期检查代理是否存活、速度是否正常。 -
代理存储(内存 /Redis/ 数据库)
常见结构:- 内存字典(适合轻量爬虫)
- Redis(适合高并发、分布式爬虫)
-
代理分配器
在每次请求前随机或轮询分配一个可用代理。
三、在异步爬虫中使用代理
以下以 aiohttp 为例:
1. 基本用法
async with aiohttp.ClientSession() as session:
proxy = "http://123.45.6.7:8080"
async with session.get(url, proxy=proxy) as resp:
html = await resp.text()
2. 将代理集成到我们之前的任务调度器
示例架构(伪代码):
class ProxyPool:
def __init__(self):
self.proxies = set()
async def add_proxy(self, proxy):
self.proxies.add(proxy)
async def get_proxy(self):
# 可以设计为随机、轮询、按评分取
return random.choice(list(self.proxies))
async def remove_proxy(self, proxy):
self.proxies.discard(proxy)
在爬虫请求结构中加入
async def fetch(session, url, proxy_pool):
proxy = await proxy_pool.get_proxy()
try:
async with session.get(url, proxy=proxy, timeout=10) as resp:
return await resp.text()
except Exception:
await proxy_pool.remove_proxy(proxy) # 剔除无效代理
raise
这样框架每次请求时自动分配代理,提高存活率。
四、构建代理验证器(异步方案)
每隔固定时间检测代理可用性:
async def verify_proxy(session, proxy):
test_url = "https://httpbin.org/ip"
try:
async with session.get(test_url, proxy=proxy, timeout=5) as resp:
return resp.status == 200
except:
return False
批量验证:
async def validate_proxies(proxy_pool):
async with aiohttp.ClientSession() as session:
tasks = []
for proxy in list(proxy_pool.proxies):
tasks.append(verify_proxy(session, proxy))
results = await asyncio.gather(*tasks, return_exceptions=True)
for proxy, ok in zip(list(proxy_pool.proxies), results):
if not ok:
proxy_pool.remove_proxy(proxy)
五、代理负载均衡策略设计
代理池不只是“随机 IP”,一个成熟的爬虫项目会加入评分系统:
| 策略 | 说明 |
|---|---|
| 随机策略 | 最简单,适合初学者 |
| 队列轮询 | 代理平等分配,可控稳定 |
| 评分策略 | 根据响应速度、失败次数动态调整 |
| 自适应策略 | 接收 429 / 403 时降低权重 |
示例评分结构:
class ProxyPool:
def __init__(self):
self.proxies = {} # { proxy: score}
def get_proxy(self):
# 选取评分最高的代理
return max(self.proxies, key=self.proxies.get)
六、防封策略(非代理层面的补充)
除了代理池,还可以加入如下反爬机制:
1. 随机 User-Agent
headers = {"User-Agent": random.choice(user_agents)}
2. 自动重试 + 指数退避
await asyncio.sleep(2 ** retry_times)
3. 自动限速与请求间隔抖动
await asyncio.sleep(random.uniform(0.5, 1.5))
4. 设置合理的并发量
并发过高是最容易触发封禁的行为。
5. 失败模式识别
常见封禁信号包括:
- status 403 / 429
- 返回验证码页
- HTML 中包含“访问过于频繁”
框架可自动捕获并触发降速逻辑。
七、总结
本节我们扩展了异步爬虫框架的能力,引入代理池与防封策略,核心收益包括:
- 大幅提升爬虫存活率
- 支持高并发下的稳定运行
- 自动化 IP 管控与自愈能力
- 针对封禁信号的智能应对
下一节我们将进一步补全爬虫框架的高级能力,包括任务持久化、失败任务恢复、以及跨进程的分布式调度设计,让你的异步爬虫具备“工业级”运行能力。