搜索抓取

搜索蜘蛛抓取:缓存协商头与 304 回访对抓取节奏的影响

蜘蛛回访一个已抓过的 URL 时,通常会带上 If-Modified-Since 或 If-None-Match。服务器若判断内容未变,可返回 304 而不传正文,从而减少传输量、降低渲染开销、缩短响应时间。本文说明 304 的作用边界、常见失效原因,以及用日志和命令行核对缓存协商的实操步骤。

搜索抓取

搜索蜘蛛抓取:缓存协商头与 304 回访对抓取节奏的影响

搜索蜘蛛回访一个已经抓过的 URL 时,通常不会无条件地把整个 HTML 重新下载一遍。它会在请求头里带上条件:If-Modified-Since 或 If-None-Match。服务器如果判断内容没有变化,就返回 304 Not Modified,不带正文。这个机制对站点和蜘蛛双方都有意义,但它经常被误解,也被错误配置。

回访请求里发生了什么

第一次抓取后,蜘蛛会记录响应中的 Last-Modified 和 ETag。下次回访时:

  • If-Modified-Since 带上上次的 Last-Modified 时间;
  • If-None-Match 带上上次的 ETag 值;
  • 两者同时存在时,服务器按自身实现优先级判断。

如果内容未变,返回 304;如果有变化,返回 200 和新的正文。需要注意的是,304 并不等于这个 URL 不用再抓,它只是省掉了正文传输。

304 省下的是什么

它主要减少三件事:带宽占用、服务器渲染或查询开销、以及响应时间。对于列表页、标签页这类模板固定但内容偶尔变化的 URL,稳定的缓存协商能让回访更快完成。但抓取预算的消耗并不能简单等同于字节数,蜘蛛仍要发起请求、等待响应、判断状态码。因此 304 不会让一个深层页面凭空获得更多抓取机会。

把 304 当成降低服务器压力的手段是合理的,把它当成提高收录概率的手段则会失望。

常见的缓存协商失效原因

  • 动态 ETag:每次请求都生成不同的 ETag,比如把进程 ID、时间戳拼进去,导致永远无法命中。
  • Last-Modified 使用当前时间:页面没变,时间却每次都刷新,蜘蛛只能收到 200。
  • CDN 或反向代理改写头:源站返回的 ETag 被边缘节点替换,回访时对不上。
  • 压缩方式变化:同一 URL 在不同 Accept-Encoding 下产生不同 ETag,造成协商不一致。
  • 会话或个性化内容:页面里混入随机推荐、时间戳、用户态片段,使内容实际每次都变。

核对步骤

  1. 用命令行工具带条件头发起请求,例如 curl 带上 If-None-Match 或 If-Modified-Since,观察是否返回 304。
  2. 连续两次无条件请求同一 URL,比较两次响应头中的 ETag 与 Last-Modified 是否一致。
  3. 查看源站直连与经过 CDN 后的响应头,确认没有被中间层改写。
  4. 从服务器日志中筛选爬虫 UA 与 304 状态码,统计回访中 304 的比例。
  5. 对比例异常的 URL,检查模板里是否输出了时间、随机数或未登录态内容。

与 URL 发现的关系

缓存协商不直接决定某个 URL 是否被发现,但它影响蜘蛛在同一时间窗口里能处理多少请求。当大量本可返回 304 的页面被迫返回完整正文时,响应时间变长,蜘蛛在同一时段能覆盖的 URL 数量就会下降,新入口的发现节奏也可能被拖慢。反过来,如果为了追求 304 而把内容更新藏在客户端渲染里,蜘蛛拿到的 HTML 长期不变,链接入口同样会缺失。两者需要平衡。

配置时的注意点

  • ETag 应该由内容决定,而不是由请求决定。
  • Last-Modified 应反映内容真实变更时间,不要用部署时间批量刷新所有页面。
  • 对确实频繁更新的页面,允许返回 200,不必强求 304。
  • 301、404 等状态码不要返回 304,状态语义要分开。
  • 在 sitemap 的 lastmod 与页面 Last-Modified 之间保持一致,避免互相矛盾的信号。

缓存协商是抓取路径上一个不起眼但可观测的环节。定期看日志里的 304 比例和响应时间,比猜测蜘蛛为什么不来更有依据。