你是不是也遇到过这种情况:某个时间点开始,服务器日志里出现一种特征明显的UA(User-Agent),请求间隔精确到秒,访问路径顺序规整,带宽和CPU占用直线上升。查了一圈发现不是什么攻击,而是某个搜索引擎或数据采集工具的Web机器人(Web Robot)在抓取内容。这个时候大家想到的第一道防线,十有八九是robots.txt。
我这些年跟Web机器人和robots.txt协议打了无数次交道,既做过站点方,也写过爬虫去抓别人的公开数据。只要理解了这份纯文本文件背后的协议规则,很多抓取异常、索引异常、带宽被占满的问题都能迅速定位。这篇文章想把这件事讲透:机器人的工作机制、robots.txt的语法与匹配优先级、从零配置一份线上可用的robots.txt、配套的页面级管控手段,以及我实际踩过的一些坑。站点运维、SEO人员、爬虫开发者和做流量分析的读者,都可以参考。
1. Web机器人到底在做什么:先认清它们的真面目
1.1 机器人的身份识别:UA字符串与网络特征
Web机器人本质上是一段程序,按照预设规则自动发起HTTP请求、下载网页并提取内容,不需要人工干预。大家最熟悉的类型是搜索引擎抓取机器人,也就是俗称的蜘蛛(Spider),它们负责把页面抓回去建立索引。但机器人远不止搜索引擎在用:SEO分析工具、价格监控平台、舆情监测系统、数据采集爬虫,甚至一些恶意的内容搬运工具,都是以机器人的形态在互联网上活动。
识别机器人最直接的方法是看User-Agent请求头。规范的爬虫都会在UA里暴露自己的身份,通常会带bot、spider、crawler这类关键词。举个例子,形如MyCompanyBot/2.0 (+https://yourdomain.com/bot-info)的UA,一眼就知道它是谁家的机器人。也有一些爬虫会把UA伪装成普通浏览器,这时要结合行为特征判断:单IP短时间内高频请求、并发连接数高、访问的URL模式非常规律、缺失图片等静态资源请求、浏览器指纹不完整,这些都是机器人的典型信号。
从网络层面看,机器人的IP段通常比较集中,很多抓取工具会从固定的IDC网段发起请求。通过分析访问日志里的IP归属、请求时间分布、HTTP状态码占比,可以建立一套简单的机器人识别规则。这也是我后面做访问日志监控时的基本功。
1.2 为什么必须管理机器人:收益与风险
并不是所有Web机器人都是坏事。搜索引擎爬虫带来的自然流量价值巨大,做公开资料归档的机构抓取也属于正常用途。问题出在“不加节制的抓取”上。我见过不少站点的服务器日志里,单日被同一个机器人抓取上万次,带宽被打满,正常用户访问变卡,数据库连接数耗尽,严重的时候整站宕机。还有一些采集工具专门盯着后台地址、接口路径,反复试探,这类行为虽然不是传统意义上的安全攻击,但会给运维带来大量额外工作。
所以管理Web机器人的核心目标不是“一律屏蔽”,而是分级对待。对合规、有用的机器人,用robots.txt配置合理的抓取范围;对来源可疑、负载异常的机器人,用服务器层面的限流和封禁兜底。robots.txt是这套管理机制里最高层、最公开的声明,它告诉所有遵守协议的机器人:哪些路径你可以抓,哪些路径请不要碰。
需要注意的是,robots.txt在协议上是一种“君子协定”。搜索引擎和正规爬虫会遵守,但纯粹的恶意程序根本不会看。理解这一点,你才不会把robots.txt当成安全工具——它的本职是流量治理和索引管理,安全隔离还需要防火墙、WAF和访问控制去解决。
2. robots.txt该怎么写:基础语法与优先级一次讲透
2.1 三个基础指令:User-agent、Allow、Disallow
robots.txt的载体是网站根目录下的一个纯文本文件,协商方式很简单:爬虫抓取某站点之前,先尝试请求https://yourdomain.com/robots.txt,拿到这份文件之后,再按文件里的规则决定抓取哪些URL。文件不在根目录、或者返回非200状态码,规范上视为不限制抓取。
文件主体由多个规则块组成,每个规则块以User-agent开头,后面跟一个或多个Allow和Disallow。User-agent指定规则适用的爬虫名,*号表示匹配所有未明确指定的爬虫,Disallow后面写禁止访问的路径前缀,Allow则相反。比如:
User-agent: * Disallow: /admin/ Disallow: /api/private/ Allow: /public/这段规则的意思很直白:所有爬虫不允许访问/admin/和/api/private/这两个目录,但允许/public/目录。这里有个基础认知:很多人以为robots.txt只能写禁止,其实Allow是非标准但被广泛支持的扩展指令,搜索引擎基本都认可,它可以在Disallow的大范围里单独放行某些URL。
还需要记住,robots.txt文件内的路径是URL路径,不是完整的URL。协议内容里不写域名和协议,只写路径部分,比如/category/page-1.html。文件本身的编码一般要求ASCII或者UTF-8,我在实际项目中都统一用UTF-8无BOM格式保存,避免部分解析器把BOM字符当成路径的一部分。
2.2 通配符与匹配优先级:80%的人在这里写错
robots.txt的通配符支持情况一直是个容易混淆的点。严格意义上,早期规范只支持空串和*作为User-agent的值,路径匹配本身不支持正则。但主流搜索引擎在路径规则里扩展支持了*和$两个符号:*匹配任意长度字符序列,$匹配路径结尾。比如Disallow: /*.pdf$可以禁止抓取所有以.pdf结尾的URL。
真正让人翻车的是匹配优先级。按现行的robots协议标准(RFC 9309)和主流搜索引擎的实现,同一块规则里如果多条规则同时命中某个URL,匹配逻辑是“最长匹配优先”,也就是哪条规则的前缀能匹配的字符最长,哪条生效;如果两条规则匹配长度完全相同,Allow优先于Disallow。举个具体例子:
User-agent: * Disallow: /report/ Allow: /report/2024/ Disallow: /report/2024/summary.pdf访问/report/2024/summary.pdf时,三条规则都命中,但Disallow: /report/2024/summary.pdf匹配的路径最长,所以最终结果是禁止。访问/report/2024/data.xlsx时,Allow: /report/2024/匹配长度最长,所以允许。访问/report/2023/时,只有/report/命中,所以禁止。理解“最长匹配优先”之后,很多诡异现象就能解释了——比如你写了Disallow: /a和Allow: /a/b,爬虫抓/a/b/c时,实际生效的是Allow: /a/b,而不是低优先级的Disallow: /a。
匹配过程中还有一个隐藏陷阱:大小写敏感。路径是区分大小写的,/Admin/和/admin/是两个完全不同的路径。如果你在robots.txt里写了Disallow: /Admin/,而站点里实际路径是/admin/,那这条规则形同虚设。
2.3 容易忽略的语法细节与规范
注释行以#开头,可以放在任意位置,但注意不要在路径中间插入注释,否则路径会被截断。每行指令末尾不要画蛇添足加空格或回车换行符,有些解析器会做trim,有些不会;稳妥起见统一不留尾随空格。
文件大小方面,规范建议robots.txt不要超过500KiB,实际上绝大多数正常站点的robots.txt只有几百字节到几KB。如果文件太大,爬虫可能只解析前面一部分就放弃,导致后面的规则失效。我还见过一些站点把海量禁止路径全部塞进去,维护很痛苦,结果部分搜索引擎只读取了开头规则。
robots.txt里还允许出现Sitemap:指令和一个对应的值,用来指向站点地图的URL。它不隶属任何User-agent块,写在文件任意位置都可以。搜索引擎看到这个指令,会主动去拉取Sitemap文件了解站点URL结构,对收录效率有直接帮助。我个人建议在robots.txt最后加上一行Sitemap: https://yourdomain.com/sitemap.xml。
另外有一个叫Crawl-delay的扩展指令,许多但不是所有爬虫支持。它用来告诉对方两次请求之间的最短间隔秒数,比如Crawl-delay: 10表示希望爬虫每10秒请求一次。注意,如果某个爬虫不支持这个指令,它会直接忽略;因此不能把Crawl-delay当成可靠的限速工具,服务器层的限流才是兜底方案。
3. 实战:从零配置一份robots.txt并完成校验
3.1 先盘点站点结构再动笔
很多人的第一份robots.txt是抄来的,这其实没问题,但抄之前至少要搞清自己站点有哪些路径。我习惯先做一份简单的站点清单:统计站点的目录结构,哪些是面向用户的核心栏目,哪些是内部后台、接口、临时文件目录。分类的时候重点考虑三个问题。
第一,核心内容路径一定要对搜索引擎开放。比如文章详情页、产品页、分类列表页,这类页面是索引的资产,屏蔽了等于不要流量。第二,非必要路径要坚决关闭。后台管理路径、用户中心、登录接口、购物车会话页、测试环境页面、临时生成的导出文件,这些对搜索用户没有价值,还占用抓取配额,应该屏蔽。第三,注意动态URL和带参数的URL。很多老站点的URL带有?id=123&sort=asc一类的查询参数,如果不做限制,爬虫会重复抓取大量内容相同的URL,造成抓取浪费。针对这种情况,可以在robots.txt里用*通配符把带参数的地址统一屏蔽。
盘点完成后,再决定分几个User-agent块。如果站点没有特殊诉求,写一个User-agent: *的全局块就够了。如果某些爬虫需要特殊处理,比如某个内容平台机器人抓取力度太大,可以单独为它的UA写一个块,用更严格的Disallow限定范围。注意,同一爬虫只匹配第一个出现的User-agent块,后面的块不会合并,所以不要把同一机器人的规则分散写在多个块里。
3.2 一份可直接套用的robots.txt示例
下面这份配置框架,是我在一个中等规模内容站点上实际用过的结构,加了注释方便理解:
User-agent: * Disallow: /admin/ Disallow: /login Disallow: /cart/ Disallow: /checkout/ Disallow: /account/ Disallow: /api/ Disallow: /tmp/ Disallow: /search Disallow: /*? Disallow: /user/ Allow: /public/ User-agent: SomeSpiderBot Disallow: / Crawl-delay: 30 User-agent: * Disallow: /feed/ Sitemap: https://yourdomain.com/sitemap.xml拆开看几处关键决策。Disallow: /*?用来屏蔽所有带问号的URL,也就是带查询参数的那批动态页,这一条对控制重复抓取非常有效。Allow: /public/是给那些虽然在Disallow范围之外、但希望明确放行的静态资源目录。SomeSpiderBot那个块是给某个抓取力度特别大的机器人单独设置的,Disallow: /等于告诉它整个站都不欢迎,Crawl-delay: 30进一步降低它的请求频率。
这里要提醒一点:最后那个User-agent: *块里写了Disallow: /feed/,但按照规范,前面的User-agent: *块已经声明了全局规则,后面的这一个*块对同属“未指名爬虫”的机器人并不会生效。为什么会这样写?我实际是想给“已经在上一个块匹配到的、但不属于任何已命名机器人”的那部分做一个补充声明,虽然语义上覆盖不完全,但它不影响关键路径。更严谨的写法是把所有全局规则合并成一个*块。所以上面这份文件更适合做模板,实际部署前建议按自己站点的结构重新整理,别把规则拆得过于零散。
3.3 配置好之后的验证与线上校验
写完文件后,第一步用curl模拟爬虫的行为,确保文件可以正常访问并返回200状态码:
curl -i https://yourdomain.com/robots.txt输出里应看到HTTP/1.1 200 OK,正文内容就是刚编辑好的规则。如果返回404或500,问题出在服务器配置或文件路径上,爬虫会认为没有任何限制。
第二步,做规则语义验证。主流搜索平台的站长工具里都有robots测试功能,可以输入一个具体URL,查看它最终命中的规则是允许还是禁止。这类工具能直接给出匹配到的规则行,非常直观。没有站长工具的情况下,可以自己写一个小脚本,把robots.txt规则解析后,用最长匹配优先的算法去模拟几个关键URL,尤其是那些边界路径。
第三步是观察日志验证。文件上线后,在爬虫的抓取日志里对比规则变更前后的请求分布。比如新增了Disallow: /tmp/,就该看到指向/tmp/目录的请求数量逐步降为0。需要注意的是,抓取方不一定会立刻丢弃已经排入队列的URL,所以这个降为0的过程可能需要几小时甚至几天,不要刚上线几分钟就下结论。
4. 配置完robots.txt就结束了吗:配套管控方案
4.1 meta robots标签与X-Robots-Tag响应头
robots.txt管的是“抓取”,而“索引”是另一件事。很多站点把不想被搜索收录的页面写进robots.txt,结果页面确实不被抓了,但之前已经被抓取收录的页面并不会自动从搜索结果里消失——因为robots.txt管不到索引。要管控某个具体页面是否被收录,应该用页面级的meta robots标签,或者HTTP响应头里的X-Robots-Tag。
meta robots标签放在HTML的<head>里,常见写法是<meta name="robots" content="noindex, nofollow">。noindex表示不要把这个页面放进索引库,nofollow表示不要继续跟踪页面上的链接。这里特别建议组合使用:仅设置nofollow还允许索引,仅设置noindex可能还允许抓取链接关系,明确表达“别收录”就直接两个都写上。
X-Robots-Tag则更适合动态页面、接口、静态文件这类不方便改HTML的情况,由服务器在响应头里下发。比如X-Robots-Tag: noindex。还有一种场景是防止内容被快照转载,可以在响应头里加noarchive,告诉搜索引擎不要保存页面快照。这套组合拳的优势在于粒度极细,可以精确到单个URL,而robots.txt只能按路径前缀做粗粒度控制。
实际操作中我摸索出一个经验:对要删除出索引的URL,优先用meta robots或X-Robots-Tag标noindex,同时不要把robots.txt里的对应路径Disallow掉。因为搜索引擎需要重新抓取一次页面才能看到noindex标签,如果这个路径在robots.txt里被禁止抓取,它就永远看不到这个指令,URL就会一直被收录。
4.2 抓取速率与抓取配额的协同管理
robots.txt的Disallow能挡住“该抓的别抓”,但控制不了“允许抓的路径被疯狂抓”。对允许抓取的页面,还需要关注抓取速率和抓取配额。
抓取配额(crawl budget,常说的抓取预算)是搜索引擎在某个站点上愿意投入的总抓取资源,它和站点规模、内容更新频率、页面质量、服务器响应速度都有关系。响应时间越快、有效内容越多、无效URL越少,配额就越充足、抓取效率越高。所以清理robots.txt里的无效路径、减少重复URL,本质上是在帮助搜索引擎把有限的配额用到真正有价值的页面上。
速率控制则要从两头做。一头是爬虫侧的自觉:在robots.txt里声明Crawl-delay,适合still支持该指令的爬虫。另一头是站点侧的强制:如果某个IP段或某个UA的请求速率超过阈值,在Nginx或WAF层直接拦截或限速。我个人习惯在访问日志里按UA做聚合统计,重点观察几个头部爬虫的日请求量;一旦某个爬虫请求量出现异动,就临时加一条server级别的访问规则进行限制。这种方法不依赖爬虫是否自觉,是更可靠的兜底方案。
4.3 Sitemap提交与机器人友好度的整体设计
robots.txt里写Sitemap地址只是第一步,真正提升收录效率的是稳定的Sitemap更新机制。Sitemap里应该只放“需要被收录”的URL,存放后台地址、登录页、搜索结果页的URL属于自找麻烦。Sitemap文件本身要输出正确的Lastmod时间,不要每次都返回相同时间戳;搜索引擎判断页面更新频率时,这个字段是重要依据。
把这一整套东西想清楚之后,站点的“机器人友好度”就上来了:robots.txt定义了抓取边界,meta robots和X-Robots-Tag定义了索引边界,Sitemap负责告诉搜索引擎哪里有新内容,服务器限速保障了资源稳定性。任何一个环节缺失,都可能在日志里体现为“抓取量暴涨但索引量不涨”或者“核心页面迟迟不被抓取”。
5. 爬虫不听话?常见问题排查与实操记录
5.1 规则写对了但爬虫不遵守怎么办
明明robots.txt里已经Disallow: /tmp/,日志里却还是看到爬虫在抓取/tmp/下的文件。遇到这种情况,先别急着骂爬虫,按下面几个方向排查。
先确认robots.txt是否真正生效。用浏览器直接访问https://yourdomain.com/robots.txt,看内容是不是线上最新版本。很多站点上了CDN,robots.txt被CDN缓存了老版本,爬虫拿到的是之前的规则,当然不会执行新配置。这时需要刷新CDN缓存,或者给robots.txt设置较短的缓存时间。
再确认规则是否匹配到了真实路径。注意URL里大小写、末尾斜杠、百分号编码的差异。比如站点的真实路径是/tmp%2Fdownload/,robots.txt里写的是/tmp/download/,两者不匹配。建议从访问日志里复制几条真实请求路径,逐字比对,而不是凭印象判断。
排除这些之后,如果某款爬虫仍然无视robots.txt,很可能它本身就属于不遵守协议的采集器。这类机器人没有谈判空间,直接在服务器防火墙或WAF里按UA、IP段封禁,同时开启速率限制。我的一个经验是,封禁要按IP段做,因为很多采集工具会轮换IP,单纯封单个IP效果很差。
5.2 路径大小写与编码导致的误伤
robots.txt匹配是大小写敏感的,这是最常见的误伤来源。假设站点之前有一批链接是/Product/123,后来重写成/product/123,但robots.txt里还留着Disallow: /Product/,那重写后的页面反而被放行了,该屏蔽的没屏蔽;反过来也可能出现新路径被老规则误杀的情况。建议所有路径规则都按站点当前真实使用的URL写,不能凭记忆。
还有一类问题是URL编码。路径里如果包含中文、空格、特殊字符,在robots.txt里应该写URL编码后的形式,比如空格写成%20。但有些爬虫在解析robots.txt时会把%20解码成空格再匹配,有些则直接拿编码后的字符串做比较,行为不一致。为了避免问题,我在配置时尽量不把带特殊字符的路径直接写进robots.txt,而是改用更高层级的目录前缀,或者干脆用meta robots标签控制这一类页面。
5.3 改动后不生效:缓存与生效时机
还有一个高频问题是“改了robots.txt,为什么一周了还是老样子”。除了CDN缓存,搜索引擎对robots.txt本身也有缓存机制,有的爬虫会缓存数小时到数天,不是每次抓取都重新拉取。这种延迟是正常的,不要反复改文件折腾。
确认思路是这样:先用curl看线上文件内容,确认服务器侧已经更新。然后看爬虫日志里请求robots.txt的时间戳和频率,如果好几天都没有请求,那说明抓取方还没触发重新读取;如果每天都在请求但内容还是旧的,多半是中间层缓存。我的处理办法是在服务器配置里对robots.txt设置Cache-Control: no-cache之类的响应头,让中间缓存尽量失效,但最终效果还是取决于爬虫自身的缓存策略,急不来。
5.4 常见问题速查表
下面整理了一份我在工作里反复用到的问题排查表,按频率排序:
| 症状 | 可能原因 | 解决方案 |
|---|---|---|
| 爬虫仍在抓取已Disallow目录 | 规则未生效、CDN缓存旧文件、路径大小写不匹配 | 用curl核对线上文件,比对真实URL,刷新缓存 |
| 页面被收录但robots.txt禁止了 | 之前抓取时未被禁止,robots.txt不影响已收录页面 | 改用meta robots的noindex,或提交索引移除请求 |
| 带参数的URL被抓取过多 | 没有屏蔽动态URL | 增加Disallow: /*?规则,清理无效参数 |
| 某爬虫请求量异常大 | 对方忽略robots.txt或Crawl-delay | 在WAF/IP层面限速或封禁,按IP段操作 |
| 抓取量大但收录量不涨 | 页面质量低、无有效Sitemap、重复URL多 | 检查Sitemap有效性,清理重复内容,优化页面加载速度 |
| robots.txt不小心屏蔽了核心页面 | 规则过度宽泛,或通配符理解错误 | 用最长匹配规则单独放行核心路径,或临时删除整条规则 |
最后说一点我个人的习惯:robots.txt不是一次写好后就能放手不管的静态文件。站点每次改版、换路由、加栏目,我都会把线上robots.txt重新过一遍,配合访问日志观察抓取频率的变化。这份文件确实是最轻量级、最公开的治理手段,但它也有边界——它只是君子协议,不能替代页面级的索引控制,更不能替代服务器安全策略。只有搞清楚它的能力和局限,才能在实际运维里把它用到恰到好处。