download_delay是全局固定值,仅控制同域名请求最小间隔;差异化限速需结合concurrent_requests_per_domain与autothrottle动态调节,后者按域名独立计算延迟并响应服务器负载。

DOWNLOAD_DELAY 是全局配置,不能按域名单独设置
DOWNLOAD_DELAY 只作用于整个爬虫项目,对所有域名一视同仁。它控制的是「同一域名下两个请求之间的最小间隔」,但这个间隔值本身是写死在 settings.py 里的,不支持表达式或条件判断。所以你无法直接写 DOWNLOAD_DELAY = {'example.com': 2.0, 'api.site.org': 0.5} —— 这会报错,Scrapy 不识别这种结构。
想按域名差异化限速?必须用 CONCURRENT_REQUESTS_PER_DOMAIN + AutoThrottle 组合
真正能实现「对不同域名施加不同节奏」的方案,是靠并发数限制配合自动节流:
-
CONCURRENT_REQUESTS_PER_DOMAIN控制每个域名最多同时发几个请求,这是硬性闸门 -
AUTOTHROTTLE_ENABLED = True启用后,Scrapy 会为每个域名独立计算下载延迟:响应越慢,延迟越长;出错越多,延迟越保守 -
AUTOTHROTTLE_TARGET_CONCURRENCY设为 1.0~4.0 之间更稳妥,数值越低,对单域名越“温柔”
例如,对反爬强的 news.sina.com.cn,可单独在 spider 中覆盖设置:
class SinaSpider(scrapy.Spider):
name = 'sina'
custom_settings = {
'CONCURRENT_REQUESTS_PER_DOMAIN': 1,
'AUTOTHROTTLE_TARGET_CONCURRENCY': 1.0,
'AUTOTHROTTLE_START_DELAY': 3.0,
}
RANDOMIZE_DOWNLOAD_DELAY 的真实效果常被高估
默认开启的 RANDOMIZE_DOWNLOAD_DELAY 并不是“在 DOWNLOAD_DELAY 基础上加减浮动”,而是把延迟缩放到 0.5 × DOWNLOAD_DELAY 到 1.5 × DOWNLOAD_DELAY 区间——前提是 DOWNLOAD_DELAY > 0。如果设了 DOWNLOAD_DELAY = 0,它就完全失效。
更关键的是:这个随机化只影响「人为设定的固定延迟」,对 AutoThrottle 动态算出来的延迟毫无作用。后者始终按服务器实际响应时间实时调整,不掺杂随机。
绕过 settings.py 的硬编码?用 downloader middleware 动态干预
如果真需要每个请求都走自定义逻辑(比如根据 response.status 或 request.url 主机名决定 sleep 多久),就得写下载中间件:
- 在
process_response里检查域名和状态码 - 用
time.sleep()强制阻塞当前线程(⚠️注意:这会拖慢整个 downloader,慎用) - 或者更合理的方式:抛出
IgnoreRequest,再用scrapy.Request(..., dont_filter=True)带上新meta['retry_delay']重新入队
这种方案灵活但难维护,仅适用于极少数必须精确控制单个请求节奏的场景,比如对接有严格 QPS 配额的 API。
最易忽略的一点:Scrapy 的「下载延迟」测量起点是 TCP 连接建立完成,终点是 HTTP 响应头收齐——它不包含 response body 下载时间。这意味着大文件响应可能让实际请求间隔远大于配置值,而 AutoThrottle 对此无感知。










