搜索抓取

蜘蛛重复抓取同一批 URL:Last-Modified、ETag 与 304 能省下什么

蜘蛛反复访问同一批 URL 是常态,服务器其实有机会少干活。Last-Modified、ETag 与 304 响应决定了蜘蛛能否跳过重复下载,也影响它把有限的访问留给新内容。本文讲清这几个头部的实际作用、站点常写错的地方,以及 CDN 缓存插入后该怎么看日志。

搜索抓取

蜘蛛重复抓取同一批 URL:Last-Modified、ETag 与 304 能省下什么

重复抓取是常态,不是浪费

站点跑一段时间后,日志里出现最多的一类请求,往往是蜘蛛对同一批 URL 的反复访问。首页、栏目页、热门详情页,可能一天被走好几遍,而新发布的页面反而迟迟没人来。这不代表蜘蛛在乱跑,它本来就需要定期回访,确认内容有没有变化。真正的问题在于:这些回访里有多少是必须整页下载的,有多少其实只要回一句“没变”就够了。

站点能控制的部分就在这里。通过缓存校验头部,让蜘蛛在内容未变时拿到一个很短的 304 响应,而不是重新下载整个 HTML,既能减轻服务器压力,也能让蜘蛛把有限的访问次数更多分给新 URL。

Last-Modified 与 ETag 各管什么

当蜘蛛再次请求同一个 URL 时,通常会在请求头里带上两个信息:If-Modified-SinceIf-None-Match。前者对应站点上一次返回的 Last-Modified,后者对应上一次返回的 ETag。服务器拿到这两个值后自行判断:内容没变就返回 304,内容变了就正常返回 200 加新内容。

  • Last-Modified:一个时间戳,表示页面最后一次改动的时间。粒度是秒,够用但不精确,同一秒内的多次修改可能看不出来。
  • ETag:一段标识,通常由文件内容或版本号算出。粒度更细,但必须是稳定的——同样的内容必须算出同样的值。
  • 304:不带响应体,只有头部。抓取工具拿到它就知道可以继续用本地缓存版本。

两者可以一起用,也可以只用其中一个。只要逻辑自洽,蜘蛛都能处理。

304 与抓取节奏的关系

从站点侧看,304 省的是带宽和渲染开销;从蜘蛛侧看,省的是解析和比对成本。当一个页面长期不变,反复返回 304,等于告诉蜘蛛“这里暂时不用细看”,它对这类地址的回访频率往往也会自然调整。反过来,如果站点明明内容没变却每次都返回 200 加完整页面,蜘蛛每次都得重新读一遍,抓取资源就被消耗在原地踏步上。

要注意的是,返回 304 并不代表这个 URL 会被忽略。它仍然是一次有效的抓取记录,只是没有新内容。所以不必担心“返回 304 会不会让蜘蛛觉得页面不存在”。

容易写错的地方

  • ETag 每次请求都变。有些框架把进程号、时间戳、随机数混进 ETag,导致每次算出来的值都不一样。这样蜘蛛永远匹配不上,条件请求形同虚设,甚至可能被判断为页面频繁变动。
  • Last-Modified 永远等于当前时间。动态渲染的站点容易出现这个问题,页面没改,时间戳却一直在跳,蜘蛛每次都会认为是新内容。
  • 时间格式不标准。Last-Modified 需要是标准的 HTTP 日期格式,用本地时间或自定义格式写,蜘蛛无法解析,等于没给。
  • 返回 304 却带了响应体。这种情况容易引发解析异常,也可能被中间层改写成 200。
  • 静态资源与 HTML 用了同一套规则。图片、CSS 这类带版本号的资源适合长缓存,HTML 则需要更及时地校验,混在一起配置容易两头都不对。

缓存层插进来之后

如果站点前面挂了 CDN 或反向代理,蜘蛛看到的 304 可能来自缓存节点,而不是源站。这时候日志分析会变得模糊:源站看到的是回源请求,节点日志看到的才是蜘蛛请求。排查时建议分层看——先确认节点是否透传了 If-None-Match,再确认源站是否真的按内容比对。有些配置会把请求头里的校验字段丢掉,结果就是每个蜘蛛请求都变成一次完整的回源。

另外,缓存节点如果返回的是自己拼的 304,ETag 可能与源站不一致。跨层校验时,最好对比节点响应头与源站响应头,看两者是否指向同一份内容标识。

一段可落地的检查思路

  1. 挑三个长期不更新的页面,手动请求一次,记录返回的 ETag 和 Last-Modified。
  2. 带上这两个值再请求一次,看是否稳定返回 304。
  3. 隔一天再重复一次,确认 ETag 没有随时间漂移。
  4. 对比服务器访问日志与应用日志,确认 304 不只在节点层出现。
  5. 发布新内容后,检查这几个 URL 是否及时从 304 变回 200。
304 的价值不在于让蜘蛛少来,而在于让蜘蛛每次来的时候,都不用为没变化的页面付出完整代价。把头部写稳,比一味追求抓取次数更实在。