bigywater.tech
Scrapy · 4

settings 的优先级:默认值、项目、spider、命令行谁覆盖谁

DOWNLOAD_DELAY 在 settings.py 里写了 1,spider 里写了 2,命令行又 -s 3,到底谁生效?这篇把六档优先级逐一设置、逐一运行,还验证了字典设置的合并方式、-s 的字符串坑和冻结时机。

6 档
SETTINGS_PRIORITIES:0 / 10 / 15 / 20 / 30 / 40
41
spider 里要压过命令行 -s 需要的优先级数值("cmdline" 40 会输)
'False'
-s 传来的字符串,settings["X"] 当 if 用是真,必须 getbool

六档优先级

实测 · 本机执行输出
  default   0
  command  10
  addon    15
  project  20
  spider   30
  cmdline  40

优先级数值在 scrapy/settings/__init__.py 的 SETTINGS_PRIORITIES 里。同一个设置被多次写入,数值大的生效,相等则后写的覆盖先写的。

同一设置的不同来源

实测 · 本机执行输出
  设置来源                                                                     生效值     优先级
  新建项目的 settings.py 原样(模板里写着 DOWNLOAD_DELAY = 1)                         1      20
  模板的那一行删掉,什么都不设                                                         0       0
  settings.py 里 =1                                                       1      20
  settings.py =1 + spider.custom_settings =2                             2      30
  settings.py =1 + custom_settings =2 + 命令行 -s =3                      '3'      40
  settings.py =1 + addon =4(addon 优先级 15 < project 20)                   1      20
  只有 addon =4                                                            4      15
  -s =3,spider.update_settings 里 set(…, 5, "cmdline")                  '3'      40
  -s =3,spider.update_settings 里 set(…, 5, 41)                           5      41
  settings.py =1 + 旧写法 spider 属性 download_delay = 2                      2      30   警告:The 'download_delay' spider attribute is deprecated. Use the DOWNLOAD_DELAY setting instead.

项目 settings.py 20、custom_settings 30、命令行 -s 40、addon 15。scrapy startproject 的模板里已经带着 DOWNLOAD_DELAY = 1,新项目默认每个请求之间有 1 秒延迟。用 update_settings 想压过 -s,优先级数字要比 40 大。

字典设置整体替换

实测 · 本机执行输出
  settings.py 里 {A: 543},spider 里没有
      用户层(getdict)    {'proj.mw.A': 543}
      与 BASE 合并后(只列 A/B/Retry) {'RetryMiddleware': 550, 'A': 543}
  settings.py 里 {A: 543},custom_settings 里 {B: 544}
      用户层(getdict)    {'proj.mw.B': 544}
      与 BASE 合并后(只列 A/B/Retry) {'RetryMiddleware': 550, 'B': 544}
  settings.py 里 {A: 543},custom_settings 里 {RetryMiddleware: None}
      用户层(getdict)    {'scrapy.downloadermiddlewares.retry.RetryMiddleware': None}
      与 BASE 合并后(只列 A/B/Retry) {'RetryMiddleware': None}

低优先级的字典不会和高优先级的字典合并。想“在已有中间件之外再加一个”,要在 spider 里把完整的字典重写一遍。关闭内置组件用 None。

字符串与类型

实测 · 本机执行输出
  -s MYFLAG=…     settings["MYFLAG"] 原值 / 当 if 用 / getbool / getint
  'False'         'False' truthy=True getbool=False getint=ValueError
  '0'             '0' truthy=True getbool=False getint=0
  ''              '' truthy=False getbool=ValueError: Supported values for boolean settings are 0/1, Tru getint=ValueError
  'true'          'true' truthy=True getbool=True getint=ValueError
  '1'             '1' truthy=True getbool=True getint=1
  'no'            'no' truthy=True getbool=ValueError: Supported values for boolean settings are 0/1, Tru getint=ValueError
  -s MYLIST=a,b,c -s 'MYDICT={"x": 1, "y": [2]}' -s MYF=0.5 -s MYI=12 →
      RESULT getlist ['a', 'b', 'c'] | getdict {'x': 1, 'y': [2]} | getfloat 0.5 | getint('12') 12

命令行传来的都是字符串,用 getbool/getint/getlist/getdict 取值。直接 settings["X"] 当布尔用会把 'False' 当成真。

冻结

实测 · 本机执行输出
  from_crawler: frozen = False; set 成功,读到 7
  start(): frozen = True; set 失败: TypeError Trying to modify an immutable Settings object
  start() 读到 DOWNLOAD_DELAY = 7 (from_crawler 里设的 7 保留着)

spider 的 from_crawler 里设置还可以改,start() 里已经冻结,再改抛 TypeError。

找到项目设置

实测 · 本机执行输出
  $ cat scrapy.cfg
    # Automatically created by: scrapy startproject
    #
    # For more information about the [deploy] section see:
    # https://scrapyd.readthedocs.io/en/latest/deploy.html
    
    [settings]
    default = proj.settings
    
    [deploy]
    #url = http://localhost:6800/
    project = proj
  项目根目录                                         → mybot
  项目的子目录 proj/spiders/                          → mybot
  项目外的空目录                                       → scrapybot
  项目根目录 + SCRAPY_SETTINGS_MODULE=other_settings → otherbot

scrapy.cfg 里的 [settings] default 指向设置模块;子目录里也能向上找到;SCRAPY_SETTINGS_MODULE 环境变量优先。

分步演示

设置的优先级
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.8 / Scrapy 2.19.0 / Twisted 26.4.0 / lxml 6.1.3 / parsel 1.12.1(临时虚拟环境);所有请求只发给本机自己起的测试服务器(127.0.0.1,端口 9960 以上,不访问任何真实网站);服务器可以按实验需要制造延迟、重定向、压缩、断连等行为,并记录收到的原始请求;每个实验在临时目录里新建 Scrapy 项目或单文件 spider,命令输出来自真实的 scrapy 进程;计时用 time.perf_counter,数字每次运行会有小幅抖动。每个情形都是 scrapy startproject 新建的项目里一次 scrapy crawl,spider 在 start() 里打印 crawler.settings 的值和优先级(getpriority);addon 是一个只实现 update_settings 的类,通过 ADDONS 设置加载
    • 没有验证:update_settings 里 "cmdline" 输给 -s 的原因只是读代码和跟踪 BaseSettings.set 的调用栈(CrawlerRunner.create_crawler 在 spider.update_settings 之后又把命令行设置 update 进来,相等优先级后写的覆盖先写的),没有逐版本核对;addon 的 update_pre_crawler_settings;多个 crawler 同进程时设置是否互相影响(源码里 Crawler 用 settings.copy(),没有专门测);SCRAPY_ 开头的其它环境变量;settings 的 pickle/序列化
    京ICP备2026067502号-1京公网安备11010502063487号