robots.txt 写错了,可能比不写更糟
很多站长对 robots.txt 的态度是"反正搜索引擎自己会找",或者从别处复制一份模板扔到根目录就完事。实际上,robots.txt 是你唯一能主动控制爬虫行为的官方通道,而它写错一次,可能让整站收录腰斩——而且过程完全静默,不会有任何报错。
这篇文章不讲基础语法(网上到处都是),只讲那些真正会让你掉收录、掉流量的具体场景,以及怎么用日志验证你写的规则真的生效了。内容站的 robots.txt 和 sitemap 是一套组合拳,一起讲才完整。
一、先明确 robots.txt 的能力边界
这是最多人误解的地方。必须清楚 robots.txt 能做什么、不能做什么:
- 它是请求,不是命令。 遵守与否完全取决于爬虫自愿。Google、Bing、百度都遵守,但恶意采集器、SEO 分析工具、AI 训练爬虫(部分)根本不看。
- 它不能阻止索引。 这是最致命的误解。
Disallow只阻止抓取,不阻止索引。如果站内有其他页面链接到了被 Disallow 的 URL,搜索引擎完全可以只靠外链锚文本把它索引进结果页——只是它抓不到内容,于是显示一个没有摘要的空结果。这叫"无摘要收录",对站点质量是纯负面。 - 正确做法:想阻止索引用
<meta name="robots" content="noindex">,且该页面必须允许被抓取(否则爬虫看不到这个 meta 标签)。Disallow 和 noindex 不能同时用,这是 SEO 里最经典的互斥陷阱。
所以规则是:
- 想让它不出现在搜索结果里 → 页面可抓取 +
noindex。 - 想让它被爬虫完全忽略(比如后台、API、测试目录)→
Disallow,并且确保站内没有任何链接指向它。
二、内容站 robots.txt 的推荐骨架
下面这份是给个人内容站/博客用的,可以直接改改就用:
User-agent: *
Allow: /
# 后台与管理入口,彻底封闭
Disallow: /admin/
Disallow: /action/
Disallow: /install.php
# 带参数的重复页面,避免抓取预算浪费
Disallow: /*?replyTo=
Disallow: /*?*&replyTo=
Disallow: /*?page=*
Allow: /*?page=1$
# 站内搜索与动态查询,无限组合会产生海量 URL
Disallow: /search/
Disallow: /*?s=
# 功能性路径
Disallow: /feed/
Disallow: /rss.xml
Disallow: /trackback/
# 不想被索引但可被抓取的,用 noindex 处理,不在这里 Disallow
Sitemap: https://www.example.com/sitemap.xml逐条解释几个容易踩坑的点:
1. 通配符 * 和结尾锚定 $
Disallow: /*?page=* 会拦掉所有带分页参数(含 page=1)的 URL。Allow: /*?page=1$ 前面的 Allow 优先规则把它放出来——这里体现了 robots 的匹配原则:匹配最长的规则优先,长度相同时 Allow 优先。所以 Allow: /*?page=1$ 比 Disallow: /*?page=* 更具体时,page=1 是可抓取的。
2. 注意 * 不能匹配 / 吗?
可以匹配,robots 的 * 匹配任意字符序列包括斜杠。这和 shell 不一样,很多人按 shell 的直觉去理解结果就错了。
3. 关于 Crawl-delay
Google 官方已不遵守 Crawl-delay(它有自己的抓取速率算法,在 Search Console 里设置)。Bing 部分遵守。百度基本不看。所以不要在 robots.txt 里写 Crawl-delay 来"限速",那只会给你的日志加一行噪音。真正要限速,用 Nginx 的 limit_req 按 UA 做,这才是有效手段。
4. 关于 AI 爬虫
近两年新增了一批高频爬虫:GPTBot、ClaudeBot、CCBot、Google-Extended、Bytespider、PerplexityBot 等。它们抓取量往往比搜索引擎大得多。是否要拦,取决于你的策略:
# 屏蔽 AI 训练爬虫,节省带宽
User-agent: GPTBot
Disallow: /
User-agent: ClaudeBot
Disallow: /
User-agent: CCBot
Disallow: /
User-agent: Bytespider
Disallow: /但要注意一个现实:不想被训练和想被 AI 搜索引用是两件事。如果你希望自己的内容出现在 ChatGPT、Perplexity 的回答里,那允许抓取是前提。这个取舍没有标准答案,但一定要"有意识地选",而不是复制别人模板时无意中拦掉了。
三、用 Nginx 日志验证 robots.txt 是否真的生效
写完规则不看效果,是最大的浪费。验证方法和上一节的开通日志同理,从 access.log 里直接看爬虫行为。
第一步:看爬虫读 robots.txt 的状态码
grep -i 'robots.txt' /var/log/nginx/access.log | awk '{print $9, $1, $NF}' | sort | uniq -c | sort -rn | head -20必须全部是 200。 如果出现 403、404 或 500,那再完美的规则也等于零——爬虫拿不到规则,就默认"什么都能抓"。
常见的 404 原因:WordPress/Typecho 的重写规则把请求劫持了、做了 CDN 但没把 robots.txt 加入缓存白名单、或者用了 WAF 拦掉了非浏览器 UA。这三条都要排查。
第二步:确认 Disallow 目录真的没被抓
# 统计爬虫对 admin/action/search 的抓取次数
grep -iE 'googlebot|bingbot|baiduspider' /var/log/nginx/access.log \
| grep -E '/admin/|/action/|/search/' \
| awk '{print $1, $7}' | sort | uniq -c | sort -rn | head如果这里出现了大量记录且状态码是 200,说明有爬虫无视了你的规则,或者你漏掉了某个 UA。这时候上 Nginx 层面做硬拦截:
# /etc/nginx/conf.d/bot-block.conf
map $http_user_agent $bad_bot {
default 0;
~*Bytespider 1;
~*SemrushBot 1;
~*AhrefsBot 1;
~*MJ12bot 1;
}
server {
if ($bad_bot) { return 403; }
}注意 map 必须写在 http 块里,if 在 server 块里 return 是少数被官方认可的 if 用法之一。不要用 if 去包 proxy_pass,那是著名的灾难源头。
第三步:统计爬虫抓取预算被谁吃了
这是诊断"收录慢"最直接的一招:
grep -i 'googlebot' /var/log/nginx/access.log \
| awk '{print $7}' | sed 's/[0-9]\+/N/g' | sort | uniq -c | sort -rn | head -25把 URL 里的数字替换成 N 做聚合,能看出爬虫的抓取预算花在哪个 URL 模式上。如果发现大量预算花在 /tag/、/page/N、?replyTo=N 这类低价值页面,说明抓取预算被浪费了——这些正是该在 robots.txt 里 Disallow 或者加 noindex 的。反之如果预算集中在你的核心文章页,说明 robots.txt 起到作用了。
这个分析可以做得很细,比如只统计正文页的抓取频率,看新文章多久被爬一次。
四、sitemap.xml:不是生成完就完事
sitemap 的作用是告诉搜索引擎"这些 URL 存在,请来抓",尤其对新站和内链较浅的页面价值巨大。但它也有限制,很多人不知道:
- 单个 sitemap 文件最多 50,000 个 URL,且未压缩不超过 50MB。超了要拆分成 sitemap index。
<lastmod>只有在你诚实填写时才有用。如果每次生成都写当前时间,Google 会学会忽略你的 lastmod,之后你的真实更新也失去优先级。这是最容易被自己搞坏的一个字段。- sitemap 里的 URL 必须与该页面的 canonical 完全一致。如果 sitemap 写 http 而页面 canonical 是 https,或者 sitemap 带 www 而站内链接不带,这些 URL 会被判为"替代页面",白白浪费。
一个可靠的 lastmod 生成方式
用文件真实修改时间来填,而不是生成时间:
<?php
// 生成 sitemap 片段,lastmod 取文章真实更新时间
foreach ($posts as $p) {
printf(
"<url><loc>%s</loc><lastmod>%s</lastmod></url>\n",
htmlspecialchars($p['permalink'], ENT_QUOTES, 'UTF-8'),
date('c', $p['updated']) // 注意是 updated 而非当前时间
);
}如果内容站的数据库里有 modified 字段,就用它。没有的话建议加上——它对 sitemap 的准确性影响很大。
拆分与索引
<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap><loc>https://www.example.com/sitemap-posts-1.xml</loc>
<lastmod>2026-09-01</lastmod></sitemap>
<sitemap><loc>https://www.example.com/sitemap-posts-2.xml</loc>
<lastmod>2026-09-20</lastmod></sitemap>
<sitemap><loc>https://www.example.com/sitemap-tags.xml</loc></sitemap>
</sitemapindex>拆分的好处不只是 50,000 上限:爬虫可以只重新抓取 lastmod 变化的那个分片,整体带宽和时间都省。对每天更新多篇的站点,按月份或按分类分片是很好的策略。
五、robots.txt 与 sitemap 的交叉陷阱
这两者一起用时,下面这些矛盾必须避免,每一条我都在真实站点上见过:
- sitemap 里列了被 Disallow 的 URL。爬虫拿到 sitemap 来抓,被 robots 拦住,结果是一条"已发现但被 robots.txt 阻止"的提示,纯浪费。生成 sitemap 时要用同一套规则过滤。
Disallow: /或者Disallow: /*这种全局禁抓,然后又期待站点被收录。这几乎等于向搜索引擎申请"请删除我的站"。生产环境绝对不要出现。- 把 sitemap 放在被 Disallow 的目录下,比如 Disallow 了
/assets/而 sitemap 在/assets/sitemap.xml。爬虫连地图都拿不到。 - 多域名/多协议混写。sitemap 里同时出现 http 和 https、带 www 和不带 www,会被判为跨域名指引,效果打折。只写一种,就是你的 canonical 形式。
- robots.txt 本身被缓存太久。CDN 上把 robots.txt 的缓存设成 7 天,你改了规则但搜索引擎拿到的还是旧的。建议 robots.txt 的缓存时间控制在 1 小时以内,并在 CDN 上加一条强制覆盖规则。
六、上线后的验证清单
curl -I https://你的域名/robots.txt,确认返回 200、Content-Type: text/plain,且没有意外跳转到 404 页。curl -s https://你的域名/robots.txt肉眼核对语法,特别检查是否有中文标点(全角冒号、全角引号)——这类字符爬虫会直接忽略整行,是极隐蔽的坑。curl -I https://你的域名/sitemap.xml,同样确认 200 和application/xml。- Search Console 的 robots.txt 测试工具 + 已编入索引页面报告,对比改动前后两周的数据。
- 用 access.log 的三条 awk 命令验证爬虫实际行为,而不是"假设"。
- 两到四周后复查:抓取预算分布是否向你期望的 URL 模式倾斜。
robots.txt 和 sitemap 是低成本高杠杆的两件事:写好一次,长期生效;写错一次,静默掉收录。绝大多数"收录变慢""新文章不收录"的问题,根源都能在这两个文件加一条日志分析里找到答案。先验证,再优化,顺序别搞反。