给蜘蛛池入口页做缓存优化时,常有人问:服务器对搜索蜘蛛返回 304 Not Modified,爬虫是不是就不再看这个页面了?入口页里新增的目标链接,还能不能被发现?这个问题要拆成两件事看:爬虫手里有没有缓存副本,以及缓存校验信息准不准。
先搞清楚 304 是谁触发的
304 不是服务器主动发的,而是爬虫带着校验信息来问“页面变了吗”,服务器回答“没变”。常见的校验字段有两组:If-Modified-Since 对应 Last-Modified,If-None-Match 对应 ETag。爬虫只有在之前成功抓取并保存了这些校验信息的前提下,下一次请求才会带上它们。
所以还有一种情况是:爬虫从没抓过这个入口页,手里没有缓存,请求里不会带校验头,服务器也就无从返回 304,只能正常返回 200 和完整 HTML。
返回 304 时,爬虫手里的链接还在不在
爬虫收到 304,意味着它会沿用本地缓存的那份 HTML,不会重新下载正文。由此有两个结果:
- 如果上一次抓取时那份 HTML 已经解析出了链接,这些链接早已进入待抓取队列,不会因为这次 304 被撤销。
- 如果入口页在这次改动中新增了链接,而服务器仍然回答“没变”,新链接就不会被发现,因为爬虫根本没看到新版 HTML。
也就是说,304 本身不会伤害已经发现的 URL,真正的问题在于缓存校验信息与实际内容不一致。
哪几种情况容易出问题
Last-Modified 更新不及时
有些程序把 Last-Modified 写成页面首次生成时间,或者写死成某个固定值。入口页加了新链接,HTML 确实变了,但 Last-Modified 没动,爬虫一问,服务器还是回 304,新链接自然浮不出来。
CDN 或缓存层提前拦截
如果 CDN 把入口页缓存住,并且对带校验头的请求直接回 304,源站的新内容可能根本没有参与判断。这类问题通常表现为:本地直接访问源站能看到新链接,走 CDN 域名却看不到。
链接靠脚本动态生成
如果入口页的链接需要执行 JavaScript 才会插入 DOM,而爬虫基于缓存副本判断页面未变化、跳过重新处理,新链接的发现会更慢。静态可读的链接在这种场景下更稳妥。
长期只拿到 304,抓取频率被下调
多次返回 304 说明内容稳定,爬虫通常会降低对这个入口页的抓取频次。这本身不是惩罚,但如果站点长期依赖这个入口页发现新 URL,抓取节奏变慢会直接影响发现速度。
怎么排查和调整
- 看服务器或 CDN 日志里入口页的 304 占比。如果长期接近 100%,而你确实在持续更新入口页,先怀疑校验信息不对。
- 对比入口页 HTML 的实际内容指纹与 Last-Modified、ETag 的生成逻辑,确认内容变化时校验值一定会变化。
- 确认 304 是源站返回的还是 CDN 返回的,逐层排查,不要只看一次浏览器开发者工具的结果。
- 关注目标 URL 的首次发现时间有没有变慢,可以把日志按天对比。
更实用的做法
入口页不需要频繁变动,稳定通常是好事;关键是变了就让爬虫知道,没变就别制造变化。
- 每次更新入口页内容后,确认 Last-Modified 或 ETag 同步更新,不要手动写死。
- 不要为了催抓取频繁修改 Last-Modified、频繁全量返回 200,这会消耗抓取配额,也容易让爬虫判断页面状态不稳定。
- 重要目标 URL 尽量多通道暴露:入口页 HTML 里保留可读的 a 标签链接,再配合 sitemap 一起用。
- 入口页改动前后记录新链接出现的大致时间,方便判断缓存策略有没有拖慢发现。
304 不是坏事,它说明缓存机制在工作。真正需要盯住的是缓存校验信息是否如实反映了页面内容的变化。
如果入口页内容长期稳定、校验信息准确,304 只减少了无效传输,不会让已经存在的链接消失。发现变慢时,先查校验逻辑和缓存层,而不是急着关掉缓存或者频繁改动页面。