自定义下载中间件实现动态代理切换

核心代码实现

在Scrapy项目的middlewares.py文件中,创建如下下载中间件类,实现代理的动态获取、挂载、失效检测与自动重试逻辑:

# 在 middlewares.py 文件中

import random
import requests
from scrapy import signals

class DynamicProxyMiddleware:
    """
    动态代理中间件
    功能:自动获取、随机切换代理,并在代理失效时触发重试
    """
    def __init__(self, proxy_api_url=None, proxy_list=None):
        # 代理来源:可以是一个API接口,也可以是一个静态的代理列表
        self.proxy_api_url = proxy_api_url
        self.proxy_list = proxy_list or []
        # 简单缓存,避免每次请求都去获取新代理
        self.current_proxy = None

    @classmethod
    def from_crawler(cls, crawler):
        # 从 settings.py 中读取配置
        api_url = crawler.settings.get('PROXY_API_URL')
        proxy_list = crawler.settings.get('PROXY_LIST', [])
        middleware = cls(proxy_api_url=api_url, proxy_list=proxy_list)
        crawler.signals.connect(middleware.spider_closed, signal=signals.spider_closed)
        return middleware

    def get_proxy(self):
        """从API或列表中获取一个可用的代理IP"""
        # 方案1:从API获取(推荐用于动态代理池)
        if self.proxy_api_url:
            try:
                # 这里以常见的返回纯文本IP:PORT的API为例
                response = requests.get(self.proxy_api_url, timeout=5)
                if response.status_code == 200:
                    proxy = response.text.strip()
                    # 确保返回的格式正确
                    if proxy and ':' in proxy:
                        return f"http://{proxy}"
            except Exception as e:
                print(f"从API获取代理失败: {e}")

        # 方案2:从静态列表随机选择(适合少量固定代理)
        if self.proxy_list:
            return random.choice(self.proxy_list)

        return None

    def process_request(self, request, spider):
        """在请求发出前,为它挂载代理"""
        # 如果没有缓存代理或当前代理已失效,则获取一个新的
        if not self.current_proxy:
            self.current_proxy = self.get_proxy()

        if self.current_proxy:
            # 关键步骤:将代理设置到request的meta中
            request.meta['proxy'] = self.current_proxy
            spider.logger.debug(f'使用代理: {self.current_proxy}')

    def process_response(self, request, response, spider):
        """检查响应,如果代理访问受限则清除缓存,触发重试"""
        # 当响应码是403、429等访问受限特征时,认为当前代理已无法正常访问目标网站
        if response.status in [403, 429, 503]:
            spider.logger.warning(f'代理 {self.current_proxy} 访问受限,状态码: {response.status}')
            self.current_proxy = None  # 清除失效代理

            # 获取当前重试次数
            retry_times = request.meta.get('retry_times', 0)
            max_retry_times = request.meta.get('max_retry_times', 3)

            if retry_times < max_retry_times:
                # 创建一个新的请求对象,并增加重试计数
                new_request = request.copy()
                new_request.meta['retry_times'] = retry_times + 1
                new_request.dont_filter = True  # 允许重试已访问过的请求
                spider.logger.info(f'正在重试请求,第 {retry_times + 1} 次重试')
                return new_request
        return response

    def process_exception(self, request, exception, spider):
        """处理请求过程中的异常(如超时、连接错误)"""
        spider.logger.error(f'请求异常: {exception},代理 {self.current_proxy} 可能失效')
        self.current_proxy = None

        # 这里也可以加入和上面类似的重试逻辑
        retry_times = request.meta.get('retry_times', 0)
        if retry_times < 3:
            new_request = request.copy()
            new_request.meta['retry_times'] = retry_times + 1
            new_request.dont_filter = True
            return new_request
        return None

    def spider_closed(self, spider, reason):
        """爬虫结束时清理资源"""
        self.current_proxy = None
        spider.logger.info("爬虫关闭,代理中间件已清理")

项目配置与中间件激活

在项目的settings.py文件中,完成中间件激活、代理来源配置与重试参数优化:

# settings.py

# 1. 激活自定义动态代理中间件,禁用Scrapy默认代理中间件

DOWNLOADER_MIDDLEWARES = {
    'your_project_name.middlewares.DynamicProxyMiddleware': 543,  # 替换为你的项目名称
    'scrapy.downloadermiddlewares.proxy.ProxyMiddleware': None,  # 禁用默认代理中间件
}

# 2. 配置代理来源(推荐使用服务商API)
# 填写代理服务商提供的API链接,可直接返回可用IP:PORT

PROXY_API_URL = 'https://your-proxy-service-api.com/get'

# 3. 配置重试相关参数,增强业务健壮性

RETRY_TIMES = 3  # 全局默认重试次数
RETRY_HTTP_CODES = [500, 502, 503, 504, 408, 403, 429]  # 需要触发重试的状态码

关键机制与原理解析

代理注入逻辑

process_request方法中,通过request.meta['proxy'] = proxy_url将代理绑定到请求对象,Scrapy引擎会自动使用该代理发送请求,实现请求环境的隔离与切换。

失效检测与清理

中间件通过process_response方法检查响应状态码(如403、429),判断代理是否出现访问受限情况。一旦检测到失效,立即清除当前缓存的代理,确保下次请求时获取新的可用代理。

自动重试的闭环处理

当代理失效或请求出现异常(如超时、连接错误)时,中间件会构造新的请求对象并返回,新请求会重新进入下载流程,再次经过代理中间件获取新代理,形成“失效-切换-重试”的完整闭环,保证爬虫任务的连续性。

落地优化与注意事项

代理来源的选择建议

生产环境强烈推荐使用专业代理服务商的API获取代理,而非静态代理列表。API方式能保证IP资源的新鲜度与可用性,无需自行维护复杂的代理池检测与更新逻辑,大幅降低开发与运维成本。

请求行为的合规优化

即使使用代理IP,也需控制请求频率,配合Scrapy的DOWNLOAD_DELAY设置合理的下载延迟(1-2秒),并开启RANDOMIZE_DOWNLOAD_DELAY让请求间隔随机化,使爬虫行为更接近真实用户,降低访问受限率。

额外的健壮性增强方案

可在get_proxy方法中增加代理验证逻辑,比如通过请求稳定的公共网站验证代理的可用性,避免将失效代理注入到请求中,进一步提升爬虫的成功率。

适配Scrapy场景的专业代理服务

Scrapy爬虫业务对代理IP的新鲜度、可用性、稳定性要求极高,青果网络作为国内领先的企业级代理IP服务商,深耕行业十一年,其能力能完美适配这类场景的需求:

海量纯净IP资源与动态调度

青果网络国内每日更新600万+纯净IP资源,覆盖全国300多个城市与地区;海外拥有2000W+纯净全球HTTP与代理IP资源池,能为Scrapy爬虫提供源源不断的新鲜可用代理,避免因IP资源枯竭导致任务中断。

低延迟与高可用的代理服务

青果网络采用自研代理服务端,所有IP上线前均经过检测验证,网络延迟低于100毫秒,可用率高达99.9%。同时采用业务分池技术,整体业务成功率比行业平均高出约30%,能有效减少Scrapy请求的失败次数,提升爬虫效率。

无缝对接的API接口支持

青果网络提供标准化的API接口,可直接对接Scrapy的自定义代理中间件,无需额外开发复杂的代理池维护逻辑,只需在settings.py中配置API地址即可实现动态代理的自动获取与切换,大幅降低开发成本。

全周期的技术支持与测试服务

青果网络提供国内代理IP6小时测试、全球HTTP2小时体验服务,技术团队7×24小时在线支持,能快速响应并解决Scrapy爬虫过程中遇到的代理适配、请求失败等问题,保障业务的稳定运行。

总结

在Scrapy中实现自动切换代理IP,核心是通过自定义下载中间件完成代理注入、失效检测、自动重试的全流程逻辑。生产环境推荐使用专业代理服务商的API获取代理,配合青果网络的海量纯净IP资源、高可用服务与标准化API,能大幅提升爬虫任务的稳定性与效率,同时降低开发与运维成本。

常见问题解答

Q1:Scrapy中使用静态代理列表和API动态代理有什么区别?
A1:静态代理列表适合测试或小规模爬虫场景,但IP易失效,需要手动维护更新,成本较高;API动态代理(如青果网络提供的接口)能自动获取新鲜可用的IP资源,适合生产环境的大规模爬虫业务,可有效保证请求的连续性与稳定性。

Q2:自定义代理中间件需要和哪些Scrapy配置配合使用?
A2:需要配合激活自定义中间件、配置代理来源(API或静态列表),同时可设置RETRY_TIMES(重试次数)、RETRY_HTTP_CODES(触发重试的状态码)、DOWNLOAD_DELAY(下载延迟)等参数,进一步增强业务的健壮性。

Q3:使用代理IP进行Scrapy爬虫时需要注意哪些合规问题?
A3:需严格遵守目标网站的robots协议与使用规则,控制请求频率避免影响网站正常运行;选择合规的代理服务商(如青果网络)使用纯净无风险的IP资源,避免因代理IP的合规性问题导致爬虫任务受阻。

青果网络代理IP - CTA Banner
点赞(33)
不同业务场景下代理IP服务选型需聚焦性能、场景适配与合规运维三大核心维度
代理IP 国内代理 国外代理IP 爬虫代理 海外代理IP
2026-04-03

选择代理IP需聚焦可用率等5核心维度,匹配业务场景。青果网络拥600万+国内、2000W+全球纯净IP,99.9%可用率,适配多类业务。

爬虫与公开数据采集场景代理IP类型、选型及合规全解析
爬虫代理 代理IP 动态代理 长效IP IP池
2026-04-03

爬虫/数据采集需代理IP保障稳定,分免费(仅测试)、短效动态(90%场景首选)、长效独享(特殊场景),选型重稳定合规,青果网络提供高可用企业级代理方案,提升采集效率。

爬虫新手代理IP选型与避坑全指南
爬虫代理 代理IP 隧道代理 动态代理 静态代理
2026-04-03

爬虫新手选代理IP,遵循“场景匹配-类型选择-质量验证”逻辑,优先稳定合规的付费代理(如青果网络),首选隧道代理,避开免费代理。

高带宽海外代理IP选购核心维度与场景适配指南
海外代理IP HTTP代理 海外IP 爬虫代理 代理IP池
2026-04-03

选购高带宽海外代理IP,需匹配带宽、IP类型、可靠性指标。青果网络拥千兆跨境专线、2000W+纯净全球IP,适配跨境电商等多场景,支持2小时试用,适配国内用户海外业务。

返回
顶部