蜘蛛第一次抓完页面后,后续重访并不总是重新下载整份 HTML。如果服务器支持条件请求,蜘蛛会带上 If-Modified-Since 或 If-None-Match,服务器判断内容没变就回一个 304,告诉对方内容还是原来那份。理解这套机制,能解释很多日志里看起来奇怪的现象。
条件请求的两种凭证
Last-Modified 与 If-Modified-Since 用时间做比较,粒度到秒;ETag 与 If-None-Match 用内容标识做比较,粒度更细。两者可以同时存在,服务器按自己的规则决定用哪个。对抓取来说,关键不是用哪一种,而是这个值要稳定:内容没变时,凭证也不能变。
常见的凭证不稳定
- ETag 由进程 ID、时间戳或随机数生成,每次请求都不同,蜘蛛每次都被判定为新内容。
- Last-Modified 取自动态生成时间,页面内容没变但时间一直在跳。
- 反向代理或 CDN 改写了响应头,回源与边缘的 ETag 不一致。
- WAF 拦掉了 If-None-Match 请求头,服务器每次都返回 200 加完整正文。
这几种情况不会直接导致抓取失败,但会让蜘蛛做很多无效下载,占用抓取额度,也可能让它误判页面的更新频率。
日志里怎么确认
在访问日志中按状态码统计即可:304 的数量、对应的 URL,以及同一 URL 上 200 与 304 的交替情况。
- 挑一批内容基本不变的页面,看它们重访时是否稳定返回 304。
- 如果全是 200,先看响应头里的 ETag 是否每次都变,再看中间层有没有改写。
- 如果 304 比例异常高但页面其实已经改过,检查缓存层是否给出了过期的凭证。
304 表示内容没变,不表示没被抓。它同样是蜘蛛的一次有效访问,只是没有传输正文。
和 Sitemap 的 lastmod 配合
Sitemap 里的 lastmod 是给蜘蛛的另一种提示,和 HTTP 层的凭证本质上是同一件事的两种表达。如果 lastmod 写着昨天更新,而服务器对同一 URL 一直回 304,两个信号就互相矛盾。更新内容后,让 lastmod、Last-Modified、ETag 三者一起变化,是最省事的做法。
几个值得注意的细节
- 304 不传输正文,蜘蛛拿到的是它缓存里的副本。如果副本已经过期而服务器仍回 304,更新可能被延迟感知。
- 对频繁变动的页面,比如列表页和首页,缓存头不宜设置过长,否则蜘蛛看到的一直是旧版本。
- 对稳定不变的内容页,允许 304 是好事,既省带宽,也能让蜘蛛把额度留给别的 URL。
- 服务器不稳定时,条件请求可能返回 5xx 或超时,这时要按服务器问题排查,而不是当成缓存配置问题。
小结
把 304 理解成一次确认而不是一次抓取失败,排查思路就清晰了:先确认凭证是否稳定,再确认中间层有没有改写响应头,最后看 Sitemap 的 lastmod 和 HTTP 层是否说了同一件事。三处对齐,蜘蛛对页面更新状态的判断才不会来回摇摆。