Scrapy自动限速AutoThrottle完全指南

📂 所属阶段:第三阶段 — 攻防演练(中间件与反爬篇)
🔗 相关章节:Downloader Middleware · 代理IP池集成 · 反爬对抗实战

目录


AutoThrottle是什么?

AutoThrottle 是 Scrapy 内置的下载中间件,专门用来替代传统的静态延迟 DOWNLOAD_DELAY。它会根据目标网站的实时响应情况,动态调整每次请求之间的等待时间,以及同时发出的请求数量,让你的爬虫表现得像一位“有礼貌的人类”:

  • 不会死板地傻等,白白浪费时间
  • 也不会疯狂发包,把服务器压垮或触发反爬

你可以把它想象成根据路况自动调整车速的巡航系统——路况好时快一点,堵车时自动减速,永远保持安全距离。

为什么不直接用静态延迟?

如果所有请求都使用固定的延迟,会出现三种尴尬局面:

  1. 低峰期太亏:网站负载轻、响应飞快,但你的爬虫还在按 5 秒一次“摸鱼”,严重拖慢效率
  2. 高峰期反而添乱:网站本身已经吃力,固定延迟并不会感知到服务器变慢,仍然保持原有的请求节奏,很容易触发限流或封禁
  3. 新网站很难预判:每换一个目标站点,你都得猜一个“合适”的延迟。猜小了容易被封,猜大了又浪费时间

AutoThrottle 的出现,正好解决了这些难题——让爬虫自己学会“看情况”决定快慢。


工作原理(简化版)

AutoThrottle 的内核并不复杂,你可以用下面三个步骤快速理解它的运行逻辑:

  1. 起步阶段
    按照你设置的 AUTOTHROTTLE_START_DELAY(初始延迟)发出第一个请求。

  2. 持续学习
    在爬取过程中,AutoThrottle 会默默记录每个域名下所有请求的平均响应时间,就像在学习“这个网站通常反应有多快”。

  3. 动态调速
    实际等待时间会这样计算:
    目标延迟 ≈ 平均响应时间 ÷ 目标并发数
    (目标并发数默认为 1.0,意味着对单个站点来说,大致是“等到上一个请求有了响应,再发下一个”)
    最终延迟会被严格限制在 START_DELAYMAX_DELAY 之间。

此外,AutoThrottle 还会遵守全局和单域名的并发上限,不会让你的爬虫“放飞自我”。

小提示:目标并发数越大,单站点同时发出的请求就越多,效率更高但风也更险;反之越小,就越保守。


核心配置参数

上手 AutoThrottle 非常简单,只需要在 settings.py 中打开开关,再微调几个关键参数即可。

# 1. 核心开关(强烈建议在生产环境和调试阶段都开启)
AUTOTHROTTLE_ENABLED = True

# 2. 延迟范围控制(最重要的两个参数)
AUTOTHROTTLE_START_DELAY = 3   # 初始请求间隔(秒)。普通站点 1-2,强反爬站点 5-10
AUTOTHROTTLE_MAX_DELAY = 60    # 最大请求间隔(秒)。防止异常状况下无限等待

# 3. 目标并发数(决定你是“激进派”还是“稳重派”)
AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
# 例如设为 2.0,单站点最多可以同时发出 2 个请求,效率翻倍但被禁风险也会增加

# 4. 调试开关(开发时务必打开,实时监控限速情况)
AUTOTHROTTLE_DEBUG = True
# 开启后,控制台会持续输出当前延迟、响应时间等统计信息

避坑小贴士

  • 不要再单独设置 DOWNLOAD_DELAY
    AutoThrottle 会接管请求延迟,两者同时存在时可能互相干扰,反而让速度变得不可控。

  • 目标并发数不要超过全局并发的 1/3
    例如全局 CONCURRENT_REQUESTS = 16,那目标并发数建议控制在 5 以内,避免单个域名吃光所有连接资源。

  • 最大延迟不要设得过大
    如果延迟飙到 120 秒以上,大概率是服务器已经把你“拉黑”了,此时不如主动暂停任务、换 IP,而不是继续傻等。


场景化高级配置

不同网站的“包容度”完全不同,我们可以根据目标特性套用下面几套模板。

1. 保守模式(适合高防护网站:微博、知乎、小红书等)

AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_START_DELAY = 8
AUTOTHROTTLE_MAX_DELAY = 120
AUTOTHROTTLE_TARGET_CONCURRENCY = 0.5   # 极度保守:发一个请求,等大约 2 倍响应时间,再发下一个
CONCURRENT_REQUESTS = 2                 # 全局同时最多 2 个请求
CONCURRENT_REQUESTS_PER_DOMAIN = 1      # 单个域名严格串行,绝不“多嘴”

2. 平衡模式(适合普通网站:新闻站、博客站、中小电商)

AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_START_DELAY = 2
AUTOTHROTTLE_MAX_DELAY = 60
AUTOTHROTTLE_TARGET_CONCURRENCY = 2.0   # 单站点允许 2 个请求同时跑
CONCURRENT_REQUESTS = 16
CONCURRENT_REQUESTS_PER_DOMAIN = 4

3. 激进模式(适合公开 API、数据接口、对自己的 IP 池有信心时)

AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_START_DELAY = 0.5
AUTOTHROTTLE_MAX_DELAY = 15
AUTOTHROTTLE_TARGET_CONCURRENCY = 5.0   # 单站点同时发出 5 个请求
CONCURRENT_REQUESTS = 32
CONCURRENT_REQUESTS_PER_DOMAIN = 8

无论选择哪种模式,都建议先用保守参数跑一跑,观察到稳定后再逐步放开。


最简单的自定义限速

如果内置的 AutoThrottle 还不能满足你的需求——比如你想区分普通页面和 AJAX 接口的请求,或者给每个请求加上一点“随机抖动”来避免过于规律的访问行为——这时你不需要从零重写整个中间件,只需继承内置的 AutoThrottle 并微调核心方法即可。

下面的示例展示了两个常用技巧:为 API 请求降低延迟,并为全部请求添加 ±20% 的随机浮动。

import random
from scrapy.downloadermiddlewares.autothrottle import AutoThrottle

class CustomAutoThrottle(AutoThrottle):
    def _adjust_delay(self, slot, delay):
        """
        在原始延迟计算基础上,加入自己的逻辑:
        1. 若请求发往包含 'api' 或 'ajax' 的域名,则降低延迟
        2. 对最终延迟加上 ±20% 的随机抖动,避免形成固定频率而被反爬识别
        """
        # 先获取 AutoThrottle 原本计算出的基础延迟
        base_delay = super()._adjust_delay(slot, delay)

        domain = slot.domain

        # 1. 特殊域名降延迟
        if 'api' in domain or 'ajax' in domain:
            base_delay *= 0.6   # API 请求只保留 60% 的延迟

        # 2. 随机抖动(最有效的反规律手段之一)
        jitter = random.uniform(0.8, 1.2)
        final_delay = base_delay * jitter

        # 3. 再次套上安全边界,防止过于极端
        final_delay = max(self.start_delay * 0.5, min(final_delay, self.max_delay))

        return final_delay

启用自定义中间件

settings.py 中替换内置版本,保持优先级一致即可:

DOWNLOADER_MIDDLEWARES = {
    # 禁用内置 AutoThrottle
    'scrapy.downloadermiddlewares.autothrottle.AutoThrottle': None,
    # 启用自己的定制版本(优先级沿用 400)
    'myproject.middlewares.CustomAutoThrottle': 400,
}

常见问题与最佳实践

常见问题

1. 爬虫速度还是很慢,怎么办?

从这几个方向逐一排查:

  • 是否还保留着 DOWNLOAD_DELAY 设置?赶紧删掉,它会和 AutoThrottle 打架。
  • AUTOTHROTTLE_TARGET_CONCURRENCY 是否设得太保守?可以先尝试上调到 2~5。
  • 全局的 CONCURRENT_REQUESTS 会不会卡住了脖子?比如一直沿用默认的 16,如果机器性能允许且网站承受得住,可以提高到 32 甚至 64。

2. 明明开了 AutoThrottle,IP 还是被封了?

  • 别指望 AutoThrottle 单枪匹马解决所有反爬问题。务必搭配代理 IP 池User-Agent 随机轮换Cookie 池等手段协同作战。
  • 检查是否触发了高压线:在调试日志中观察延迟,如果延迟长期被压到 MAX_DELAY 附近,说明服务器已经非常不满,建议暂停任务 10~30 分钟,更换 IP 后再恢复。
  • 如果网站对频率极度敏感,果断切到保守模式,把目标并发数降到 0.5,实现单域名“绝对串行”。

3. AutoThrottle 的延迟数字一直在跳,正常吗?

完全正常! 因为它是基于实时统计的动态算法,刚开始数据积累少,波动会比较明显。等跑了二三十个页面后,延迟就会慢慢收敛到一个相对稳定的区间。

最佳实践

  1. 开发初期用保守模式 + 打开调试日志
    先充分摸清目标网站的响应习惯,再考虑提速。

  2. 一定要加入随机抖动
    无论是用内置的还是自定义版本,让每一次请求的间隔带点“人性化”的波动,是避免被基于固定频率检测系统识别的最经济手段。

  3. 单域名并发数尽量控制在 4 以内
    除非你抓的是明确定性为“公开 API”的服务,否则多个并发很容易被当做脚本工具而封杀。

  4. 定期保存爬取状态
    开启 Scrapy 的 JOBDIR,这样即使突然被 ban 后暂停,换完 IP 也能从断点继续跑,避免从头再来。

  5. 密切监控响应状态码
    如果连续收到 429(请求过于频繁)或 403(禁止访问),说明对方已经开始反击,应立即暂停并调整整个策略。


💡 核心要点总结
AutoThrottle 是 Scrapy 中最实用、成本最低的反爬助手之一。不要一上来就自己发明复杂的限速算法,优先把内置的 AutoThrottle 用好、调优。配合代理、UA 轮换、Cookie 池,足够解决日常爬虫中 80% 的反爬问题。遇到更特殊的场景,再基于继承扩展一点点自定义逻辑,稳扎稳打,才是最高效的方式。