做爬虫这几年有一个话题每次跟同行聊起来都会出现分歧——robots.txt到底要不要遵守。有人觉得它就是网站挂在那儿的一个摆设有人直接不闻不问等到IP被拉黑或者收到对方发来的警告邮件才后悔。我自己也经历过从“无视协议”到“认真对待”的过程。今天这篇就想跟你好好聊聊robots.txt也就是大家常说的爬虫君子协议把它的语法、原理、应用场景以及实战中怎么用Python来处理一次性讲清楚。先给新手朋友一个定位robots.txt是网站管理者放在服务器根目录下的一个文本文件用来告诉网络爬虫“哪些路径你可以抓哪些路径你不能碰”。它不是法律不依赖技术强制手段全靠爬虫方自觉遵守所以叫“君子协议”。这篇文章适合刚入门爬虫、想系统理解协议规则的开发者也适合已经写了很久爬虫、但一直没认真看过robots.txt的“老油条”。读完之后你会知道如何在代码里正确解析robots.txt、哪些细节最容易踩坑、哪些场景下“不遵守”会给自己惹麻烦以及如何从搜索引擎和网站运维两个视角反向理解这个文件。1. robots.txt到底在管什么先看它是怎么来的1.1 一件小事引发的“网络公约”1994年搜索引擎技术还处在蛮荒时代。当时很多搜索引擎蜘蛛在抓取网页时不讲章法经常把服务器压垮甚至抓走一些不该被抓的隐私目录。为了解决这个矛盾荷兰程序员Martijn Koster提出了一个简单的约定网站管理员可以在服务器根目录放一个文件蜘蛛来抓之前先读这个文件按里面的规则决定抓不抓。这个看似朴素的方案后来成了互联网事实上的行业标准。1996年它被正式纳入RFC 1945HTTP/1.0规范的附录中。虽然它从头到尾都只是“建议性”的但你去看Google、Bing、百度这些搜索引擎的官方文档都会要求开发者尊重robots.txt的规则。换句话说如果你写的爬虫不遵守robots.txt搜索引擎的爬虫可能会遵守但你自己写的数据采集脚本没人管——这就是君子协议的真正含义它约束不了代码只能约束写代码的人。1.2 为什么叫“君子协议”而不是“强制协议”技术上robots.txt没有任何强制机制。服务器只是把它当普通静态文件返回爬虫如果完全不读它网站也没有办法直接用这个文件拦截请求。所以它的“效力”完全取决于爬虫方的自觉。但也正因为如此它在某种程度上成了衡量一个爬虫开发者职业素养的试金石。你可以想象一个场景某天你写了一个爬虫把某个小型电商网站的商品详情页全部抓下来了服务器压力暴涨对方运维一查日志发现User-Agent是你自定义的Python脚本。这时候对方不会直接报警而是先发一封邮件给你附上robots.txt的内容提醒你注意抓取频率和路径限制。大多数时候事情到这一步就平息了。但如果你无视提醒继续高强度抓取那就可能面临IP封禁、法律函件等后果。我在实际项目中见过不止一次这样的纠纷。2019年某公司因为爬取另一家平台的数据对方直接拿出robots.txt作为证据起诉。虽然robots.txt本身不是法律文件但在司法实践中它常被视为“网站经营者对爬虫行为的明确授权边界”。这个信号值得每一个爬虫开发者放在心上。1.3 两种爬虫视角搜索引擎蜘蛛 vs 数据采集脚本robots.txt在设计时主要面向搜索引擎蜘蛛比如Googlebot、Baiduspider。这些蜘蛛是为了收录网页而存在的它们需要遵守网站管理员的意愿否则网站管理员可以屏蔽搜索引擎的抓取导致网站排名下降。但今天写爬虫的开发者大部分不是在做搜索引擎而是在做数据采集——比如抓商品信息、新闻内容、行业数据、社交平台公开信息等。对于这类脚本robots.txt同样值得关注。理由不只是合规更实际的原因在于如果一个网站特意在robots.txt里屏蔽了某个目录通常意味着那里的内容不适合被公开抓取强行抓取要么会遇到更强的反爬策略要么会带来法律风险。所以我的建议是无论你写的是搜索引擎爬虫还是数据分析脚本都应该在项目启动时先把目标网站的robots.txt拉出来看一遍。这是一种习惯也是一种保护自己的方式。2. robots.txt语法精讲规则不多但细节很要命2.1 四条常用指令robots.txt的语法非常简洁核心指令只有几个。先看一个最常见的例子User-agent: * Disallow: /wp-admin/ Allow: /wp-admin/admin-ajax.php Sitemap: https://example.com/sitemap.xmlUser-agent指定这条规则适用于哪个爬虫。*代表所有爬虫。Disallow禁止访问的路径。可以写完整路径也可以写目录前缀。Allow在Disallow限制内允许放行的路径。注意Allow在早期协议里没有是后来补充的用来实现更精细的控制。Sitemap声明网站的sitemap地址方便爬虫更快发现内容。这不是用来限制访问的而是主动引导。文件里可以有多组User-agent块每个块内可以有多条Disallow和Allow。匹配规则是按顺序从上到下谁的规则更具体谁优先。2.2 通配符与路径匹配规则robots.txt还支持两个通配符*匹配任意字符序列$匹配行尾。不过通配符的支持程度在不同爬虫间有差异Google是明确支持的百度和Bing有些版本支持不完整。所以尽量只用标准功能不要依赖通配符。路径匹配的规则有几个关键点大小写敏感。/User和/user是两个完全不同的路径。在写规则时要注意和实际URL保持一致。根路径是“/”。Disallow: /表示禁止爬取整个站。空路径表示允许所有。Disallow:后面没有内容等于没有限制。路径匹配是前缀匹配。Disallow: /private会同时阻止/private、/private.html、/private/pic.jpg等一切以/private开头的URL。这里有一个初学者容易犯的错误Disallow: /private/和Disallow: /private看似差别不大实际影响范围完全不同。前者只屏蔽/private/目录下的路径后者覆盖所有以/private开头的URL包括/private_fund这种页面。我刚入行时就在这上面吃过亏站长把/admin/写成了/admin结果整个/admin_area都被搜索引擎拒收了。2.3 一个容易被忽略的Crawl-delay指令Crawl-delay是用来告诉爬虫每次请求之间需要间隔多少秒的指令。它不在最初的协议版本里是后来Yandex、Bing等搜索引擎带起来的。User-agent: bingbot Crawl-delay: 10这个指令对搜索引擎爬虫比较有意义对于普通数据采集脚本参考价值很大——你可以从网站的Crawl-delay看出对方对抓取频率的容忍度。如果某个网站在robots.txt里写了Crawl-delay: 10而你依然用每秒钟5个请求的速度去抓即便没有触发反爬服务器日志里的异常流量也足够让对方运维注意到你。2.4 实战案例从真实网站看robots.txt的设计思路我以自己做过的一个项目为例。那时要采集某新闻门户的科技频道文章对方的robots.txt长这样简化版User-agent: * Disallow: /cpro/ Disallow: /baidu/ Disallow: /static/ Disallow: /special/ User-agent: Baiduspider Allow: / User-agent: Googlebot Allow: /这个文件清楚地告诉爬虫普通爬虫不允许抓取广告相关路径/cpro/、百度相关路径/baidu/、静态资源目录/static/和专题聚合页/special/但百度和Google的蜘蛛则可以抓全站。这就是典型的“搜索引擎友好型”配置网站希望被搜索引擎收录但不希望数据采集脚本乱抓。这种情况下采集新闻正文时只抓列表页和详情页跳过那些特殊目录既能完成任务也相对安全。反过来如果无视robots.txt去硬抓/static/下的内容大概率得到的不是你想找的新闻数据而是一堆CSS和JS文件白白消耗带宽。3. Python爬虫实操在代码里正确解析robots.txt3.1 用urllib.robotparser一行搞定解析Python标准库自带robots.txt解析模块urllib.robotparser使用起来非常简单。来看一段完整的示例代码from urllib.robotparser import RobotFileParser from urllib.request import urlopen rp RobotFileParser() rp.set_url(https://example.com/robots.txt) rp.read() user_agent MyDataSpider/1.0 url https://example.com/news/today if rp.can_fetch(user_agent, url): print(允许抓取:, url) else: print(禁止抓取:, url)核心方法就两个rp.read()从网络加载并解析robots.txt。rp.can_fetch(user_agent, url)传入你的爬虫名称和完整URL返回True或False。如果你的爬虫名称比较特殊比如自定义了一个很长的UAcan_fetch会按照robots.txt里的规则帮你匹配最合适的User-agent块。这个模块在底层已经处理好了匹配优先级和通配符逻辑比你自己手写字符串匹配可靠得多。3.2 注意robots.txt可能不存在用RobotFileParser时有一个常见的坑如果目标网站根本没有robots.txtrp.read()不会报错但rp.can_fetch()会返回什么答案是True——也就是允许抓取所有内容。这个逻辑其实是合理的没有声明限制就视为没有限制。但实战里很多网站的robots.txt不存在并不意味着网站欢迎你随便抓。它只代表网站管理员没有配置这个文件具体能不能抓、能抓多快你得结合网站规模、内容敏感度和反爬策略来判断。所以我的习惯是先请求robots.txt如果返回404就标记为“无robots.txt”再去观察网站的反爬策略。绝不因为can_fetch()返回True就毫无顾忌地高并发抓取。3.3 加一层缓存与离线解析RobotFileParser每次调用read()都会发起一次HTTP请求。如果你在爬虫里每个URL都调用一次can_fetch等于每个URL之前都额外多一次请求耗时翻倍。更好的做法是在程序启动时读取一次robots.txt把解析结果缓存到内存里。示例import requests from urllib.robotparser import RobotFileParser from urllib.parse import urlparse class RobotsCache: def __init__(self): self._cache {} def get_parser(self, base_url): if base_url not in self._cache: rp RobotFileParser() rp.set_url(base_url.rstrip(/) /robots.txt) try: rp.read() except Exception: rp None self._cache[base_url] rp return self._cache[base_url] def can_fetch(self, url, user_agent): parsed urlparse(url) base_url f{parsed.scheme}://{parsed.netloc} rp self.get_parser(base_url) if rp is None: return True return rp.can_fetch(user_agent, url)这样设计后整个爬虫生命周期内每个网站最多只请求一次robots.txt。如果网站的robots.txt内容不频繁变动这种做法能显著减少无效请求。当然如果你爬的是大规模网站集群还可以把解析结果存入Redis让多个爬虫节点共享缓存。3.4 分布式爬虫中的robots.txt处理分布式爬虫和多线程爬虫里robots.txt的处理需要统一规划。比如你用Scrapy Redis搭建了一个分布式采集系统几十台机器同时抓同一个网站所有节点都各自请求一次robots.txt不仅浪费流量还可能因为高并发触发反爬。我的做法是把robots.txt的解析结果放到Redis里用域名作为key解析后的规则列表作为value。每个节点启动时先检查Redis里有不有没有再请求并写入设置半天或一天过期。这样所有节点共享同一份规则还能动态更新。另外如果项目里有多个不同的爬虫任务比如新闻爬虫和商品爬虫可以考虑给每个任务设置不同的User-Agent再根据robots.txt里对应的规则分别判断。很多网站的robots.txt对*限制严格但对指定搜索引擎的UA比较宽松。虽然我们不伪装成搜索引擎但自定义一个有辨识度的UA本身没问题。3.5 一个容易忽略的细节User-Agent要一致RobotFileParser的匹配逻辑是纯字符串级别的它只看你传入的user_agent参数不会去检查真实请求的User-Agent请求头。也就是说下面这段代码可以正常运行rp.can_fetch(Googlebot, url) # 返回True requests.get(url, headers{User-Agent: Mozilla/5.0}) # 实际用浏览器UA但问题来了如果你用Googlebot去匹配robots.txt然后实际请求时又用别的UA这在语义上是自欺欺人。更重要的是很多网站的反爬系统会比对请求的UA和robots.txt的规则。你明明用Googlebot的身份“骗”过了robots.txt检查实际抓取时又暴露了非搜索引擎的UA这种行为很容易被识别为异常流量。正确做法是定义一个统一的UA比如MyDataSpider/1.0 (https://myproject.example.com)在can_fetch检查和实际请求中都使用这个UA。保持身份一致是做数据采集最基本的礼仪。4. 哪些场景可以忽略robots.txt哪些必须遵守边界要拎清4.1 搜索引擎与数字化存档的特殊性有一些场景业界普遍认为robots.txt的约束力需要重新审视。最典型的是Internet Archive互联网档案馆这类非营利性存档项目它抓取网页是为了历史记录和学术研究。很多网站为了存档目的会主动放行这类爬虫或者在robots.txt里给它们开绿灯。但如果你做的不是存档而是商业项目的数据采集就不建议拿“非营利”当挡箭牌。商业用途的数据采集务必先确认robots.txt的限制再评估法律风险。4.2 公开API接口与公开数据页面如果你的爬虫目标不是HTML页面而是网站自己提供的公开API接口robots.txt的限制通常不适用于API路径。因为API接口是程序化访问入口网站管理者如果不想让第三方调用通常会通过API鉴权、频率限制等机制来控制而不是靠robots.txt。例如GitHub的robots.txt里限制了/search/路径的抓取但它的公共REST API是允许授权后访问的。这种情况下抓取API数据时看robots.txt意义不大更重要的是遵守API的Terms of Service和频率限制。对于公开数据页面我的原则是robots.txt限制了不抓没限制但明显是“页面数据”的先低频率试探观察服务器响应和网站态度再决定是否加量。这里说的低频率是指每秒不超过1个请求甚至每2秒1个请求。4.3 强反爬网站认真读robots.txt反而是情报收集有些网站的反爬措施非常强比如通过JS渲染验证、滑块验证、指纹识别等机制来拦截爬虫。这类网站往往在robots.txt里写得很模糊甚至完全不写。但越是这样越值得你把robots.txt当作“情报”来分析。举个例子某招聘网站之前把/jobs/目录设置为Disallow但很多爬虫脚本依然去抓取职位列表。网站的反爬系统把这些流量识别出来做了IP段封禁。后来我仔细看它的robots.txt发现里面还特意标注了Disallow: /account/——这是在暗示账号相关页面是敏感区域。这类线索比你去试错找出敏感路径要高效得多。所以不管目标网站反爬强不强启动爬虫前花一分钟看robots.txt永远不亏。4.4 法律风险与伦理判断严格来说robots.txt并不是法律但在司法实践中确实有参考价值。爬虫相关的法律纠纷里法院经常关注一个核心问题爬虫方是否超出了网站明示的访问许可范围。robots.txt就是最典型的“明示许可范围”。在中国涉及数据爬取的法律条款主要聚焦在《反不正当竞争法》和《个人信息保护法》上。如果爬虫抓取了非公开数据、用户个人信息、或者绕过技术保护措施即便robots.txt没有明确禁止也可能构成违法。反过来robots.txt允许抓取的公开数据也未必就是绝对安全的——如果抓取频率过高导致服务器瘫痪可能涉及破坏计算机信息系统的问题。我的建议很简单robots.txt只代表网站管理者的基础意愿你可以把它当作参考下限而不是安全上限。更稳妥的边界是“不抓个人隐私、不抓需登录才能看的内容、不绕过技术保护措施、不超高频请求”。这四条守住了大部分问题都能避免。5. 常见问题与排查技巧实录5.1 问题速查表现象可能原因解决方法can_fetch返回True但网站依然封IP反爬系统按并发和频率判断不看robots.txt降低请求频率增加随机延时模拟真实用户行为can_fetch返回False但页面实际能访问robots.txt规则匹配到了前缀批量屏蔽了目录换更具体的URL路径或检查是否触及了/整站屏蔽rp.read()报超时网站屏蔽了某些UA或IP段的robots.txt访问用浏览器UA重试或从缓存中读取历史数据抓取结果里混入大量重复页面未正确处理分页参数导致URL无限膨胀在代码中加入URL去重限制最大爬取深度刚启动爬虫就被封User-Agent过于脚本化或请求头缺少常见字段完善请求头降低并发设置预热阶段先跑少量URL再逐步加量5.2 排查实录一个真实案例去年我帮一个朋友排查他的爬虫为什么频繁被封。他在爬某电商平台的公开商品列表页代码逻辑看起来没问题requests伪装了UA也设置了延时但跑了不到5分钟IP就被封了。我们第一件事就是看robots.txt。结果发现这个平台的robots.txt里对*并没有禁止商品列表页但是有两个细节第一User-agent: *块下面有一条Crawl-delay: 2说明网站期望爬虫至少间隔2秒第二/search/路径被明确Disallow了而朋友恰好是从站内搜索框对应的URL开始抓的——这个路径在robots.txt里是“禁区”。他改用商品分类导航URL、并将间隔调到3秒之后再也没被封过。这事给我一个很深的印象很多被封禁的背后不是网站“不让爬”而是你没看明白网站的规矩。5.3 独家经验robots.txt的“变与不变”robots.txt不是一成不变的。很多大站会随着业务调整、反爬策略升级而频繁修改robots.txt。如果长期运行爬虫建议定期重新拉取robots.txt对比变化。我习惯在每个爬虫任务里加一个日志记录前一天抓到的robots.txt内容和当天内容的差异一旦发现规则变化就告警提醒。另外robots.txt的获取本身也可能被反爬系统盯上。有些网站会对高频访问robots.txt的IP做标记因为正常的搜索引擎蜘蛛一天最多访问一两次而爬虫开发者容易在调试时反复请求。所以调试时可以手动下载robots.txt到本地改用RobotFileParser的本地文件解析方式rp RobotFileParser() rp.set_url(file:///path/to/robots.txt) rp.read()这样既能快速调试又不会给目标服务器增加压力。后记尊重规则才能把爬虫这条路走长做了这么久的爬虫我最大的体会是真正决定一个爬虫项目能做多长久的不是技术难度而是你有没有建立正确的规则意识。robots.txt只是这个意识里最基础的一环。它不像算法那么炫酷也不像并发设计那么有挑战性但它是你进入别人系统前的一张“门牌”——看一眼不花多少时间却能避开很多不必要的冲突。如果你刚开始接触爬虫我的建议是每次接到一个新网站先手动访问一下https://目标域名/robots.txt养成习惯。如果你已经写过不少爬虫这几天找个时间把自己经常抓的几个网站的robots.txt重新看一遍说不定会有新的发现。毕竟规则是死的人是活的尊重规则往往能让你的爬虫项目走得更远、更稳。
阅读完成 · 觉得有帮助?