重复抓取并不等于浪费
站点日志里经常能看到同一个地址被反复抓取。多数人第一反应是蜘蛛在浪费预算,但实际情况是:蜘蛛需要确认页面有没有发生变化。如果每次都要把整个 HTML 重新传一遍,对站点带宽和蜘蛛的处理资源都是消耗。HTTP 协议里本来就有一套机制用来回答“这个资源变了吗”,条件请求就是其中之一。
条件请求:蜘蛛先问一句“变了吗”
当蜘蛛之前抓过某个页面,它可能记住两个信息:响应里的 ETag 和 Last-Modified。下次再来同一个地址时,请求头里会带上 If-None-Match 或 If-Modified-Since。
- 内容没变:服务器返回 304 Not Modified,不带正文,蜘蛛只需更新一下“我确认过”的记录。
- 内容变了:返回 200 和完整正文,蜘蛛重新抓取、重新处理。
从抓取效率上看,304 是省成本的;但从“发现新内容”的角度看,304 意味着这次访问没有带来新信息。两者并不矛盾:稳定的页面用 304 回应是正常的,频繁变更的页面每次返回 200 也是正常的。
站点侧容易被忽略的几点
- ETag 生成方式:如果 ETag 里混入了请求时间、进程 ID 之类每次都变的字段,等于每次都是“新版本”,蜘蛛永远拿不到 304。
- Last-Modified 的准确性:文件时间被部署脚本整体刷新,会让所有页面看起来刚刚更新过。
- 动态拼接的页面:广告位、推荐位、随机排序的内容如果直接写进 HTML,页面每次都不一样,条件请求会持续失效。
- CDN 与源站的头不一致:边缘节点回源后改写或丢弃 ETag,也会让缓存协商失效。
- 304 响应不要带正文:有些中间层会给 304 硬塞一段内容,容易让蜘蛛判断混乱。
304 多了是不是不好
不必然。一个内容稳定的文档页,长期返回 304 是健康的,说明服务器在正确地告诉蜘蛛“不用重新下载”。真正需要在意的是该变的页面没变:比如列表页新增了文章,但返回的仍是上次的 ETag,蜘蛛就会继续用旧版本,新 URL 需要靠内链、Sitemap 等其他通路才能被发现。
判断标准不是 304 的数量,而是 304 是否与页面的真实更新节奏一致。
和抓取预算之间的关系
条件请求省下的是传输和解析的成本,不一定会减少蜘蛛访问的次数。蜘蛛依然会按自己的节律回访,只是每次拿到的数据量小一些。所以不要把“让蜘蛛少来”当目标,而是让每次访问都尽量是有效信息:该更新的页面能被识别为更新,没变的页面不重复传输。
可以落地的检查清单
- 抓几个不同类型页面(首页、列表页、详情页),用 curl 带条件头模拟一次请求,看是否返回 304。
- 检查 ETag 是否稳定:同一页面连续两次请求,ETag 应保持一致。
- 确认 Last-Modified 反映的是内容真实修改时间,而不是部署时间。
- 对比源站与 CDN 返回的头,确认没有被改写。
- 对高频更新的页面,接受它返回 200;对稳定页面,保留正确的协商头。
这些细节不显眼,但会持续影响蜘蛛每次来访拿到的东西。把条件请求理顺,属于成本不高、方向明确的基础工作。