robots.txt is not valid 到底哪里不合法:30 个 robots.txt 逐行查了一遍

robots.txt is not valid 这行报错多半不是文件写坏了,而是某一行 Google 根本没读。我们把 30 个域名的 robots.txt 抓下来,一共 10,775 条规则行,只按 Google 公开的规则判定:1 个文件以 BOM 开头,13 个用了 Google 不认的字段名,1 个对谁都回 418。

抓取与收录7 分钟读完2871 次阅读
robots.txt is not valid 到底哪里不合法:30 个 robots.txt 逐行查了一遍

实测 · 2026-09-14 · 30 个域名 · 30 个 robots.txt · 一次抓取

样本 / 口径:2026-08-15 起这个系列一直在用的同一批 30 个域名,2026-09-14 每个域名各请求一次 robots.txt,桌面 Chrome UA、不执行 JavaScript。文件按字节落盘,下面每个数字都是从落盘字节重新数出来的,不是手输的。判定只依据 Google 自己公开的规则,不看别的引擎认不认。

你在 Lighthouse 里看到 robots.txt is not valid,第一反应多半是「文件写坏了」。这份抓取里的答案不是这个:30 个文件、10,775 条规则行,真正算得上编码问题的只有 1 个文件,13 个文件用了 Google 不认的字段名,还有 1 个文件对谁都回一个错误码,那个错误码会让 Google 当作整份文件不存在。

怎么测的

每个域名的 robots.txt 请求一次,原始字节存盘,然后跑两组检查:一组看整份文件,一组逐行看。逐行那组只在能引用 Google 规范原文的地方才判失败——少一个冒号、开头有 BOM、字段名不在它支持的四个里。别的都不算错,所以下面这些数字会比 Lighthouse 报出来的小。

curl -s -o robots.txt -w "%{http_code} %{size_download}\n" \
  -A "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" \
  https://example.com/robots.txt

python3 -c "
raw = open('robots.txt','rb').read()
text = raw.decode('utf-8')
print('bytes', len(raw), 'bom', text.startswith(chr(0xfeff)))
known = ('user-agent','allow','disallow','sitemap')
for i, line in enumerate(text.splitlines(), 1):
    s = line.strip()
    if not s or s.startswith('#'):
        continue
    if ':' not in s:
        print('NO COLON    line', i, s[:60])
    elif s.split(':',1)[0].strip().lower() not in known:
        print('UNKNOWN     line', i, s[:60])
"
检查项依据结果
返回 200成功码按原样处理30 个里 29 个
能按 UTF-8 解码必须是 UTF-8 纯文本30 个里 30 个
开头没有 BOMGoogle 会忽略 BOM1 个以 BOM 开头
每行都有冒号字段 · 冒号 · 值0 个
字段名在支持列表里user-agent / allow / disallow / sitemap13 个用了别的
不超过 500 KiB超出的部分被忽略0 个

robots.txt is not valid 在 Google 文档里指的是什么

它的失败方式比这行报错温和得多。Google 不会因为一行写坏就把整份文件丢掉,它扔掉那一行,接着往下读。规范里就一句话,而这一句正是这篇文章存在的理由。

「Google ignores invalid lines in robots.txt files, including the Unicode Byte Order Mark (BOM) at the beginning of the robots.txt file, and use only valid lines.」—— Google Search Central robots.txt 规范页,Last updated 2026-08-31 UTC,2026-09-14 实取

同一页还定义了什么算合法的一行、什么算合法的一份文件:「A valid robots.txt line consists of a field, a colon, and a value.」「The robots.txt file must be a UTF-8 encoded plain text file and the lines must be separated by CR, CR/LF, or LF.」它也列了支持哪四个字段,而那句附注比列表本身更有用:「other fields such as crawl-delay aren't supported」

30 个文件里到底装了什么

30 个文件里有 10 个超过 100 条规则行;figma.com 一份文件 100,975 字节、8,901 条规则行,占 Google 会读的 500 KiB 的 19%。整批没有一份接近任何上限。真正装在里面的是 Google 一声不响丢掉的那些行。

站点字节规则行
figma.com100,9758,901
theverge.com5,658225
wikipedia.org5,283465
nytimes.com2,237204
canva.com1,917202
bbc.com1,568133
其余 24 个的中位数26217

这张表里有两行值得单独说。Wikipedia 的文件以 BOM 开头,那是三个字节,规范明写 Google 会忽略它;结果是它开头那行注释被解析成一个名为 # robots.txt for http 的未知字段,也就是说那句注释已经不属于这份文件了。Stack Overflow 的文件是唯一没返回 200 的那个,那是另一回事,下面单独说。

Google 不认的字段名有三个

30 个文件里有 13 个至少写了一个 Google 四个字段之外的字段名。这三种写法在任何地方都不会报错,因为 Google 遇到不支持的字段就是跳过——行还在文件里,爬虫从来没执行过它。

字段文件数是什么
Content-Signal8给 AI 训练与搜索偏好发信号的提案
Crawl-delay5某些引擎读的限速值,规范点名说 Google 不支持
License2指向一份许可文件,不在 Google 的字段列表里

Content-Signal 是这里最有意思的一种,因为它既不是打错字也不是遗留——它是刻意加上去的,写它的站点也知道 Google 不读。我们另有一次更大样本的统计:robots.txt 里的内容信号那次 34 个站里 7 个写了。Crawl-delay 是更老的故事,而且它的实际表现和多数人以为的相反:343 个分组里只有四条 crawl-delay,没有一条点的是 AI 爬虫。

有一个文件对谁都回 418

Stack Overflow 的 robots.txt 回的是 HTTP 418,内容只有 113 字节,我们换了三种客户端都一样:Chrome UA、curl 的默认 UA、Googlebot UA。文件本身是一份正经的 robots.txt,一行 License,然后是 User-agent: *Disallow: /

如果 Google 的爬虫收到的也是这个状态码,这份文件里的规则就不会生效。规范对客户端错误写得很直接:「Google's crawlers treat all 4xx errors, except 429, as if a valid robots.txt file didn't exist. This means that Google assumes that there are no crawl restrictions.」一份写着「全都别抓」的文件,和一个说着「没有任何限制」的状态码,不可能同时算数,而爬虫先看到的是状态码。

这一环我们在这里合不上,也不打算装作合上了。我们的请求从一个出口发出,Google 的爬虫从它自己的出口发出,一个对我们回 418 的站,对 Google 可能就回 200,我们的数据分不清这两种情况。能说的只有更窄、但仍然有用的一句:状态码是你 robots.txt 配置的一部分,而且是压过你写的一切的那一部分。

你自己的 robots.txt 该查哪几项

把上面那两段检查对着自己的文件跑一遍,然后看输出,别看规则条数。一个 400 行的文件里有一个不支持的字段,它的处境比一个只有六行、每行都合法的文件更差——那 400 行里有一条爬虫永远不会执行的规则,而且没有人会发邮件告诉你。

  1. 抓一次自己的 robots.txt,确认状态码是 200。落在 4xx 里就说明你的规则根本没被读。
  2. 按 UTF-8 解码,把所有不带冒号的行、以及字段名不在那四个里的行打出来。
  3. 看开头三个字节。如果是 EF BB BF,说明你存文件时带了 BOM,重存一次去掉它。
  4. 把依赖不支持字段的那些意图挪到支持的字段里,或者承认那几行只是装饰。
  • 先查状态码和编码,这两样决定文件剩下的部分还算不算存在。
  • 别把「校验器没报错」当成「爬虫和你读到的一样」;多数校验器只查语法,而真正会出事的是被解析器悄悄丢掉的那几行。

还有一条和上面这几条方向相反,但一样该记下来。如果你写不支持的字段是因为想让某个特定引擎认它,那就继续写——Content-Signal 就是合理的一例,它本来就是冲着 Google 之外的引擎去的。只是别再把那几行算成你对 Google 搜索的控制手段。AI 爬虫可达性检查会告诉你一个 AI 爬虫实际拿到的是什么,而你的 robots.txt 只是决定这件事的其中一层。

常见问题

你们是怎么测的?

2026-09-14 每个域名请求一次 robots.txt,桌面 Chrome UA、不执行 JavaScript、跟随跳转,响应体按字节存盘,再用上面那段脚本对存盘副本判定。样本仍是这个系列一直在用的那 30 个站;同一天里有 3 个站没抓回可用的首页,但那不影响 robots.txt 这一项,因为文件是从域名根目录取的,不经过首页。

有一行不合法,整份 robots.txt 就废了吗?

不会,而这正是麻烦所在。Google 丢掉那一行,剩下的照读,所以一个文件里有一个不支持的字段,其他规则全都照常生效。你不会收到任何报错、提醒或者报告。

那 crawl-delay 还值得写吗?

对 Google 不值得。规范列了它支持的四个字段,并点名 crawl-delay 不在里面。想让 Googlebot 慢下来,用 Search Console 里的抓取速率设置,那是 Google 真的会读的控制项。

为什么这些大站大多都过了严格检查?

因为真正难的检查做过一次就不难了:UTF-8 纯文本、每行有冒号。这批样本是 30 个有专职平台团队的大站,所以它不适合拿来估计小站上这些问题有多常见。这是本次测量的局限,不是关于整个互联网的结论。

超过 500 KiB 会怎样?

超出的部分直接被忽略,一份很长很长的文件,尾巴对爬虫来说就不存在。这批里没有一个接近上限,最大的那份 100,975 字节,大约是上限的五分之一。我们没测截断之后实际会怎样,因为要造那样一份文件,就得先发一份我们知道是坏的 robots.txt 出去。

robots.txt is not valid 到底哪里不合法:30 个 robots.txt 逐行查了一遍