bigywater.tech
Scrapy · 23

RobotsTxtMiddleware:robots.txt 的下载与等待

ROBOTSTXT_OBEY 打开后 Scrapy 具体怎么做?什么时候下载 robots.txt、下载失败怎么办、按哪个 User-agent 匹配、Crawl-delay 管不管?这篇用一个能返回各种 robots.txt 的服务器逐项实测。

False / True
内置默认值与 scrapy startproject 模板里 ROBOTSTXT_OBEY 的差别
放行
robots.txt 返回 404、500、超时、乱码时 /private 的结果
忽略
robots.txt 里 Crawl-delay: 2 对请求间隔的影响

开关与默认

实测 · 本机执行输出
  默认值(ROBOTSTXT_OBEY、ROBOTSTXT_PARSER、ROBOTSTXT_USER_AGENT):False scrapy.robotstxt.ProtegoRobotParser None
  项目模板 settings.py 里的相关行:#USER_AGENT = "proj (+http://www.yourdomain.com)" | ROBOTSTXT_OBEY = True

内置默认关闭,项目模板打开。打开后 RobotsTxtMiddleware 在每个请求前先取该 netloc 的 robots.txt(优先级 1000),解析后缓存,之后同一个 netloc 的请求直接用缓存的解析器。

被禁止的请求

实测 · 本机执行输出
  /a            通过
  /b            通过
  /private      被拒:IgnoreRequest: Forbidden by robots.txt
  /private/x    被拒:IgnoreRequest: Forbidden by robots.txt
  /privatefoo   被拒:IgnoreRequest: Forbidden by robots.txt
  服务器收到的顺序:['/robots.txt', '/a', '/b'];robotstxt stats {'forbidden': 3, 'request_count': 1, 'response_count': 1, 'response_status_count/200': 1}

不被允许的请求抛 IgnoreRequest("Forbidden by robots.txt"),不会发出,计入 robotstxt/forbidden;errback 能收到。

User-agent 匹配

实测 · 本机执行输出
  默认 USER_AGENT                     /all:通过 /free:通过 /mybot-only:通过 /scrapy-only:拒
  ROBOTSTXT_USER_AGENT=mybot        /all:通过 /free:通过 /mybot-only:拒 /scrapy-only:通过
  USER_AGENT=mybot/1.0 (+http://x)  /all:通过 /free:通过 /mybot-only:拒 /scrapy-only:通过

用 ROBOTSTXT_USER_AGENT(没设就用请求的 User-agent)去匹配 robots.txt 的组;存在匹配的具体组时 * 组不生效。

失败即放行

实测 · 本机执行输出
  robots.txt 的情形              /private  robotstxt stats / 说明
  200 正常                      被拒        {'forbidden': 1, 'request_count': 1, 'response_count': 1, 'response_status_count/200': 1};服务器收到 robots.txt 1 次
  404                         通过        {'request_count': 1, 'response_count': 1, 'response_status_count/404': 1};服务器收到 robots.txt 1 次
  500(会被重试 2 次)               通过        {'request_count': 1, 'response_count': 1, 'response_status_count/500': 1};服务器收到 robots.txt 3 次
  超时(服务器睡 2 s,超时 0.5 s)       通过        {"exception_count/<class 'scrapy.exceptions.DownloadTimeoutError'>": 1, 'request_count': 1};服务器收到 robots.txt 1 次
  200 但是 1024 字节二进制垃圾         通过        {'request_count': 1, 'response_count': 1, 'response_status_count/200': 1};服务器收到 robots.txt 1 次

robots.txt 下载失败(404、5xx、超时)或内容无法解析时,所有请求都被允许。

等待

实测 · 本机执行输出
  到达服务器的时刻(相对第一个请求,秒):/robots.txt@0.00, /a@1.02, /b@1.02, /c@1.03;总耗时 1.03 s
  meta dont_obey_robotstxt=True 的请求既不下载 robots.txt 也不受它限制(/private/x 本来会被拒绝):服务器收到 ['/private/x'],总耗时 0.01 s(robots.txt 要 1.0 s 才返回,但没有被请求)

robots.txt 下载期间,同一个 netloc 的其它请求会等待它;dont_obey_robotstxt 的请求例外。

Crawl-delay 与 Sitemap

实测 · 本机执行输出
  Crawl-delay: 2 → 四个页面请求之间的间隔(ms):[1, 1, 1](没有等 2 秒);总耗时 0.01 s
  同一个主机 127.0.0.1 的两个端口:服务器 1 收到 ['/robots.txt', '/x'],服务器 2 收到 ['/robots.txt', '/x'];robotstxt/request_count = 2

Scrapy 不使用 Crawl-delay,要控制节奏用 DOWNLOAD_DELAY 或 AutoThrottle。

分步演示

robots.txt
本步的对象

    本文用到的工具与边界

    • 本机 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,数字每次运行会有小幅抖动。服务器按需返回 robots.txt(200、404、500、睡 2 s、二进制垃圾),记录所有请求的到达时刻;并发 1;匹配实验的三组 User-agent 写在同一个 robots.txt 里
    • 没有验证:Protego 对通配符(*、$)、Allow/Disallow 优先级的细节;其它解析器(PythonRobotParser、ReppyRobotParser 等);Sitemap: 行的使用(见 SitemapSpider 那一篇);robots.txt 内容改变后的更新(中间件在爬虫运行期间不重新下载);robots_parsed 信号;HTTPS 与 HTTP 同主机是否各取一次(缓存键是 netloc,不含协议,只用 netloc 的字面推断)
    京ICP备2026067502号-1京公网安备11010502063487号