
自定义代理池中间件(灵活可控的推荐方案)
核心原理
通过process_request方法为每个请求随机分配代理IP,同时借助process_response和process_exception方法检测代理失效状态(如403、502等状态码或请求超时),自动触发更换代理并重新发起请求,从根源上保障采集任务的连续性。
中间件代码实现
在项目的middlewares.py文件中编写如下代码:
import random
import base64
class RandomProxyMiddleware:
def __init__(self, proxy_list):
self.proxy_list = proxy_list # 代理池列表
@classmethod
def from_crawler(cls, crawler):
# 从settings读取代理列表
proxy_list = crawler.settings.getlist("PROXY_LIST")
return cls(proxy_list)
def process_request(self, request, spider):
"""请求前自动设置代理"""
if self.proxy_list:
proxy = random.choice(self.proxy_list)
request.meta["proxy"] = proxy
spider.logger.info(f"使用代理: {proxy}")
# 带账号密码的代理(可选)
if "@" in proxy:
auth_str = proxy.split("//")[1].split("@")[0]
encoded = base64.b64encode(auth_str.encode()).decode()
request.headers["Proxy-Authorization"] = f"Basic {encoded}"
return None
def process_response(self, request, response, spider):
"""响应异常时更换代理重试"""
# 常见访问受限/代理失效状态码
if response.status in {403, 407, 502, 503, 504}:
spider.logger.warning(f"代理失效,状态码: {response.status},更换代理重试")
if self.proxy_list:
new_proxy = random.choice(self.proxy_list)
request.meta["proxy"] = new_proxy
return request.copy() # 重新发起请求,避免去重过滤
return response
def process_exception(self, request, exception, spider):
"""请求异常(超时/连接失败)时更换代理"""
spider.logger.error(f"代理 {request.meta.get('proxy')} 异常: {exception},更换代理")
if self.proxy_list:
new_proxy = random.choice(self.proxy_list)
request.meta["proxy"] = new_proxy
return request.copy()
配置启用步骤
在项目的settings.py文件中进行如下配置:
# 1. 定义代理池列表(也可后续通过动态方式加载)
PROXY_LIST = [
"http://123.12.13.14:8080",
"https://223.45.67.89:9090",
"http://user:pass@111.22.33.44:3128", # 带认证的代理格式
]
# 2. 启用自定义代理中间件,注意优先级设置
DOWNLOADER_MIDDLEWARES = {
# 关闭默认代理中间件,避免冲突
"scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware": None,
# 自定义代理中间件(优先级建议700-800,确保先于重试中间件执行)
"my_scraper.middlewares.RandomProxyMiddleware": 750,
# 重试中间件配置(优先级低于代理中间件)
"scrapy.downloadermiddlewares.retry.RetryMiddleware": 90,
}
# 3. 可选:重试策略配置
RETRY_TIMES = 3
RETRY_HTTP_CODES = [403, 407, 502, 503, 504]
第三方库快速实现(无需自定义开发)
scrapy-proxies:轻量随机轮换方案
适合快速搭建基础的代理轮换机制,无需编写复杂的中间件代码:
- 安装依赖
pip install scrapy-proxies - 配置
settings.pyPROXY_LIST = [ "http://ip:port", "https://ip:port", ] PROXY_MODE = 0 # 0=随机轮换,1=固定单个代理,2=自定义逻辑 DOWNLOADER_MIDDLEWARES = { "scrapy_proxies.RandomProxy": 100, "scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware": 110, }
scrapy-rotated-proxy:支持失效代理管理
具备代理失效自动拉黑、恢复的能力,适合对代理稳定性有一定要求的场景:
- 安装依赖
pip install scrapy-rotated-proxy - 配置
settings.pyROTATED_PROXY_ENABLED = True PROXY_FILE_PATH = "proxies.json" # 存储代理的JSON文件路径 DOWNLOADER_MIDDLEWARES = { "scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware": None, "scrapy_rotated_proxy.downloadmiddlewares.proxy.RotatedProxyMiddleware": 750, }proxies.json示例格式:["http://ip1:port", "https://ip2:port"]
进阶:动态代理获取与维护(生产环境适配)
从API动态拉取代理
生产环境中,固定的代理池容易出现批量失效的问题,可通过调用代理服务商的API定时拉取最新代理,确保代理池的有效性:
import requests
def fetch_proxies():
# 替换为专业代理服务商的API接口
resp = requests.get("https://api.qg.net/get_proxies?count=10")
return [f"http://{item['ip']}:{item['port']}" for item in resp.json()["data"]]
# 在自定义中间件的__init__方法中调用,或通过定时任务定期更新
# self.proxy_list = fetch_proxies()
从本地文件读取代理
若需要手动维护代理列表,可从本地文件加载,方便快速更新:
def load_proxies(file_path="proxies.txt"):
with open(file_path, "r", encoding="utf-8") as f:
return [line.strip() for line in f if line.strip() and not line.startswith("#")]
生产环境下的专业代理服务选择
生产环境中,免费代理的可用率极低、稳定性差,难以满足持续的数据采集需求,不少企业会选择专业的代理IP服务商,青果网络作为国内领先的企业级代理IP服务商,深耕行业十一年,能为Scrapy这类数据采集场景提供可靠的支持。
高可用的资源池保障
青果网络的国内代理资源基于三大运营商宽带构建,每日更新600万+纯净IP资源,覆盖全国300多个城市与地区,网络延迟低于100毫秒,可用率高达99.9%。这种高稳定性的资源池,能有效避免Scrapy采集过程中因代理失效导致的任务中断,保障采集效率。
适配不同场景的产品灵活性
青果网络提供多种代理产品类型,包括短效代理、隧道代理、静态代理等。其中短效代理适合需要频繁切换IP的大规模采集场景,隧道代理适合需要保持会话连续性的采集任务,能完美适配Scrapy不同的业务需求。
业务连续性与技术支持
青果网络采用自研代理服务端和业务分池技术,整体业务成功率比行业平均高出约30%,能有效提升Scrapy采集的成功率。同时,提供国内代理IP 6小时测试与7×24小时技术支持,在接入过程中遇到的任何问题,都能快速得到专业解答,保障任务的持续运行。
总结
在Scrapy中实现自动切换代理IP,可根据业务需求选择不同方案:自定义下载中间件适合需要高度定制化逻辑的场景,第三方库适合快速搭建基础功能,而生产环境则更推荐使用青果网络这类专业的代理IP服务商,以保障采集任务的稳定性和连续性。无论选择哪种方案,都需要注意代理格式的正确性、中间件的优先级配置,以及异常处理逻辑的完善。
常见问题解答
Q1:Scrapy中代理中间件的优先级为什么很重要?
A1:Scrapy的下载中间件是按照优先级数值从小到大的顺序执行的,代理中间件需要先于默认的HttpProxyMiddleware执行,才能确保自定义的代理设置生效,否则会被默认中间件的逻辑覆盖,导致代理切换不生效。
Q2:免费代理和专业代理服务在Scrapy采集中的核心区别是什么?
A2:免费代理的可用率通常不足30%,且容易出现延迟高、批量失效的情况,仅适合短期测试场景;专业代理服务如青果网络的IP资源经过严格验证,可用率高达99.9%,能满足生产环境下持续、稳定的大规模采集需求。
Q3:如何避免Scrapy重试请求时被去重机制过滤?
A3:在自定义代理中间件的process_response或process_exception方法中,使用request.copy()方法生成新的请求对象再发起重试,这样可以绕过Scrapy的去重过滤,确保更换代理后的请求能正常执行。