搜索抓取

304 与条件请求:蜘蛛重复抓取时怎样只传状态不传正文

蜘蛛第二次访问同一个 URL 时,如果服务器支持条件请求,可以用 ETag 或 Last-Modified 判断内容有没有变,没变就只回一个 304。本文说明这套机制怎么走、服务器返回 304 时常踩的坑,以及它对抓取效率和服务器压力的实际影响。

搜索抓取

304 与条件请求:蜘蛛重复抓取时怎样只传状态不传正文

蜘蛛再次访问一个已经抓过的 URL 时,并不一定需要把整页内容重新下载一遍。如果服务器支持条件请求,蜘蛛可以带着上一次记录的校验信息,问一句“这个页面变了吗”,没变就只回一个 304。这一步看着是技术细节,却直接关系到抓取预算和服务器带宽怎么花。

一次重复抓取里发生了什么

蜘蛛第一次抓到页面时,响应头里可能带有 ETag 或 Last-Modified,它会把这两个值连同 URL 一起记下来。下次再来时,请求头里就会出现对应的条件字段。

  • If-None-Match:携带上次记录的 ETag 值。
  • If-Modified-Since:携带上次记录的 Last-Modified 时间。

服务器判断内容没变,就返回 304 Not Modified,并且不带正文。蜘蛛拿到“没变”这个结论,继续使用已有副本,同时更新抓取时间。省下的是一次完整的正文传输。

ETag 与 Last-Modified 各自的特点

  • ETag 更贴近内容本身,能反映细微改动,但生成规则由服务器决定,站点之间不统一。
  • 弱 ETag(带 W/ 前缀)表示“语义上等价”,不保证逐字节相同。
  • Last-Modified 精度到秒,容易被模板渲染时间、时区、动态变量干扰,判断会偏粗。
  • 两者同时存在时,服务器可以按自己的优先级判断,通常 ETag 更被优先采用。
如果每次请求都生成一个新的 ETag,比如基于随机数或请求时间,等于告诉蜘蛛“每次都变了”,反而会引发更多完整抓取,效果和预期完全相反。

服务器返回 304 时的几个常见坑

  1. 返回 304 却带正文:部分框架把状态码和内容一起输出,不同中间层处理方式不一致。
  2. 中间层改写:CDN、WAF、反向代理可能剥离或重写 ETag,导致下次校验对不上。
  3. 动态 ETag:值每次都变,条件请求永远不命中。
  4. Last-Modified 不一致:同一份内容在不同节点返回不同时间,判断标准就乱了。
  5. 忽略条件请求:把带条件头的请求当普通请求处理,直接回完整页面。

对抓取效率和服务器压力的实际影响

对一个页面数量较多、内容长期稳定的站点,条件请求能把重复抓取中的传输量压下来。对蜘蛛来说,省下的是传输和解析成本,可能让同一时间窗里多走几个 URL;对服务器来说,省下的是带宽和一部分渲染开销。

但要注意:304 并不会让蜘蛛“不来抓”。它仍然是抓取配额里的一次访问,真正的收益在传输和解析环节,而不是“少记一次访问”。把它当成提高效率的优化手段更合适,不要指望靠它解决抓取量不足的问题。

什么情况下不太值得投入

内容更新频繁的页面,比如资讯流、库存和价格页,条件请求的命中率本来就低,不必为了命中率强行设计缓存策略。反过来,文档页、帮助页、老文章、静态资源这类长期不变的 URL,是比较值得把条件请求做对的地方。

自查清单

  1. 用 curl -I 查看首次响应是否带有 ETag 或 Last-Modified。
  2. 带 If-None-Match 再请求一次,确认返回 304 且没有正文。
  3. 对比 CDN 边缘节点与回源返回的头部是否一致。
  4. 确认 ETag 里不含随机数、时间戳、进程 ID 这类每次都变的值。
  5. 确认 Last-Modified 对应内容真实更新时间,而不是“当前时间”。
  6. 从服务器日志里看 304 的比例,判断条件请求是否真的生效。

条件请求只是抓取效率链条上的一环,它和 Sitemap、内链结构、服务器稳定性一起,决定蜘蛛把时间花在哪里。先把长期稳定的页面做成“可协商”的,再考虑更新频繁的部分,顺序上会轻松很多。