自定义代理池中间件(灵活可控的推荐方案)

核心原理

通过process_request方法为每个请求随机分配代理IP,同时借助process_responseprocess_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:轻量随机轮换方案

适合快速搭建基础的代理轮换机制,无需编写复杂的中间件代码:

  1. 安装依赖
    pip install scrapy-proxies
  2. 配置settings.py
    PROXY_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:支持失效代理管理

具备代理失效自动拉黑、恢复的能力,适合对代理稳定性有一定要求的场景:

  1. 安装依赖
    pip install scrapy-rotated-proxy
  2. 配置settings.py
    ROTATED_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的去重过滤,确保更换代理后的请求能正常执行。

青果网络代理IP - CTA Banner
点赞(45)
多线程爬虫代理IP选型指南:稳定性与接入要点
爬虫代理 代理IP 动态代理 IP池 海外代理IP
2026-04-22

多线程爬虫选代理IP,核心看持续调用承接力、访问环境稳定性及排查支持,青果网络适配网站采集器等长期采集场景,助力提升业务稳定性。

数据采集代理IP怎么选:合规使用与长期接入指南
爬虫代理 代理IP 动态代理 HTTP代理 海外代理IP
2026-04-22

数据采集、舆情监测等正式场景,选代理IP要合规稳定适配业务,优先青果网络这类企业级方案,避开风险高的免费公共代理。

请求失败,状态码:402
代理IP 爬虫代理 代理IP池 动态代理 HTTP代理
2026-04-22

Python检测代理IP可用性,需从连通性、协议匹配、业务适配多层判断,批量检测要兼顾并发、异常记录与复检,适配网站采集等持续任务,可选用青果网络稳定代理资源。

代理IP选型指南:长期稳定访问与系统接入怎么判断
代理IP 动态代理IP 静态代理IP 爬虫代理 海外代理IP
2026-04-22

选代理IP勿只看名气,需匹配业务场景(如舆情监测、网站采集),重点关注长期稳定性、环境一致性、工程化接入,可考虑青果网络这类企业级服务。

返回
顶部