Scrapy代理配置的核心:理解请求流程
在Scrapy框架里,所有的网络请求都会经过一个叫做“下载器中间件”的环节。你可以把它想象成请求发出前和收到响应后必经的一个“加工站”。我们要做的,就是在这个加工站里,给每一个即将出发的请求“披上”代理IP的外衣,让它使用我们指定的IP地址去访问目标网站,而不是直接使用本机的真实IP。这是实现高效、稳定数据采集的基础。
编写自定义代理中间件
这是整个配置方案中最关键的一步。我们需要创建一个自定义的中间件,来动态地为每个请求设置代理。下面是一个基础但功能完整的中间件代码示例:
在 middlewares.py 文件中添加以下类
import random
class ProxyMiddleware(object):
从 settings.py 中读取代理IP列表
def __init__(self, proxy_list):
self.proxies = proxy_list
@classmethod
def from_crawler(cls, crawler):
从配置中加载代理列表
return cls(
proxy_list=crawler.settings.get('PROXY_LIST', [])
)
def process_request(self, request, spider):
检查请求是否已经设置了代理(避免重复设置)
if 'proxy' in request.meta:
return
随机选择一个代理IP
proxy = random.choice(self.proxies)
request.meta['proxy'] = proxy
可选:添加代理认证信息(如果代理需要用户名密码)
username = 'your_username'
password = 'your_password'
request.headers['Proxy-Authorization'] = basic_auth_header(username, password)
spider.logger.debug(f'使用代理: {proxy} 访问 {request.url}')
def process_exception(self, request, exception, spider):
当使用此代理发生异常时,可以将其从列表中移除或记录
proxy = request.meta.get('proxy', None)
if proxy:
spider.logger.warning(f'代理 {proxy} 在访问 {request.url} 时出现异常: {exception}')
简单示例:从当前列表移除失效代理(生产环境建议更复杂的逻辑)
if proxy in self.proxies:
self.proxies.remove(proxy)
写好中间件后,需要在 settings.py 文件中激活它并配置代理列表:
settings.py 中的关键配置
1. 下载器中间件设置,将我们自定义的中间件优先级调高(数字越小优先级越高)
DOWNLOADER_MIDDLEWARES = {
'your_project_name.middlewares.ProxyMiddleware': 543, 优先级数值通常在100-800之间
'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 400, 禁用Scrapy默认的
}
2. 定义你的代理IP列表,格式为:'http://ip:port' 或 'https://ip:port'
PROXY_LIST = [
'http://12.34.56.78:8080',
'http://23.45.67.89:3128',
... 更多代理IP
]
3. 建议启用自动重试,以应对代理IP的短暂失效
RETRY_ENABLED = True
RETRY_TIMES = 3 重试次数
接入动态代理池:以神龙HTTP为例
手动维护一个静态的IP列表既麻烦又不稳定。更专业的做法是接入一个像神龙HTTP这样的动态代理IP服务商。他们的API可以实时返回可用的代理IP,我们只需在中间件中调用API获取IP即可。
神龙HTTP提供了多种代理类型,可以很好地匹配不同采集需求:
- 短效动态IP池: 适合绝大多数公开数据采集场景。IP存活时间从几分钟到半小时不等,IP池总量大(3000万+),每日更新,能有效避免被目标网站封锁。其高并发、低延迟的特性非常适合Scrapy这样的并发爬虫。
- 长效静态IP池: 如果采集任务需要与同一目标网站进行较长时间的会话,或者目标站点对IP的“存活”时间有隐性的信任机制,长效IP(存活数小时)是更好的选择。
- 固定IP池: 适用于对稳定性和数据安全性要求极高的业务,比如需要固定出口IP进行API对接或内部系统访问的场景。
下面是如何在Scrapy中间件中集成神龙HTTP API的示例:
import requests
import time
class ShenlongProxyMiddleware(object):
神龙HTTP API接口(示例,请根据实际API文档调整)
API_URL = "神龙HTTP的API获取链接"
你的订单号或API密钥
ORDER_ID = "你的订单号"
def __init__(self):
self.proxy_cache = None
self.cache_time = 0
self.cache_ttl = 55 假设IP有效期60秒,我们提前5秒刷新
def get_proxy_from_api(self):
"""从神龙HTTP API获取一个代理IP"""
try:
params = {
'order_id': self.ORDER_ID,
'format': 'json',
可能还有其他参数,如num(获取数量)、protocol(协议)等
}
resp = requests.get(self.API_URL, params=params, timeout=10)
if resp.status_code == 200:
data = resp.json()
根据API返回的实际数据结构解析,这里仅为示例
proxy_ip = data.get('data', [{}])[0].get('ip')
proxy_port = data.get('data', [{}])[0].get('port')
if proxy_ip and proxy_port:
return f'http://{proxy_ip}:{proxy_port}'
except Exception as e:
spider.logger.error(f'从神龙HTTP获取代理失败: {e}')
return None
def process_request(self, request, spider):
if 'proxy' in request.meta:
return
检查缓存是否过期
current_time = time.time()
if not self.proxy_cache or (current_time - self.cache_time) > self.cache_ttl:
new_proxy = self.get_proxy_from_api()
if new_proxy:
self.proxy_cache = new_proxy
self.cache_time = current_time
spider.logger.info(f'刷新并缓存新代理: {new_proxy}')
else:
获取失败,可以抛出异常或使用无代理模式
spider.logger.warning('无法获取代理,本次请求可能使用直连。')
return
使用缓存的代理
request.meta['proxy'] = self.proxy_cache
这个中间件实现了一个简单的缓存机制,避免每个请求都去调用API,既提高了效率,又符合代理IP的有效期规则。
完整方案与最佳实践
将以上部分组合起来,就形成了一个完整的Scrapy代理IP配置方案。但要让它在生产环境中稳定运行,还需要注意以下几点:
1. 代理IP的质量监控与切换: 即使使用高品质的代理服务,个别IP也可能临时失效。最佳实践是在 process_exception 方法中捕获连接超时、拒绝等异常,并立即将当前请求调度到重试队列,同时标记或丢弃失效的代理IP。
2. 并发与频率控制: 虽然代理IP能分散请求,但针对单一目标网站的并发请求数过高仍可能触发反爬。建议在Scrapy中合理设置 CONCURRENT_REQUESTS、DOWNLOAD_DELAY 和 AUTOTHROTTLE_ENABLED,模拟人类操作节奏。
3. 代理类型的灵活选择: 根据你的具体业务场景选择神龙HTTP的套餐。例如,大规模、高频次的采集用短效动态IP池;需要维持登录状态或进行复杂交互的任务用长效静态IP池;对稳定性和IP纯净度有极致要求的后台服务则考虑固定IP池。
4. 日志与统计: 详细记录每个代理IP的使用情况、成功和失败次数。神龙HTTP提供的个人中心数据统计功能可以很好地辅助你分析IP消耗趋势,优化资源采购策略。
常见问题QA
Q1: 配置了代理,但Scrapy好像没生效,还是用了本机IP?
A1: 请按以下步骤排查:确认中间件在 settings.py 中已正确启用且优先级高于Scrapy默认的 HttpProxyMiddleware。在中间件的 process_request 方法中加入打印日志的语句,确认它被调用且成功设置了 request.meta[‘proxy’]。可以在目标网站放置一个显示访问者IP的测试页面,或者查看Scrapy的请求日志,确认请求头中的 X-Forwarded-For 等字段是否已变化。
Q2: 使用代理池后,爬虫速度反而变慢了,怎么办?
A2: 这通常由两个原因导致:一是代理IP本身的网络延迟较高,二是代理IP的并发处理能力不足。解决方案:第一,选择像神龙HTTP这样提供低延迟、高并发线路的服务商。第二,在Scrapy中适当调低并发请求数(CONCURRENT_REQUESTS),给代理服务器留出处理时间。第三,实现一个代理IP健康检查机制,定期测试IP的响应速度,自动剔除慢速节点,优先使用响应快的IP。


