常见问题

蜘蛛池入口页返回 304,搜索蜘蛛还会重新读取里面的目标链接吗

搜索蜘蛛抓取入口页时返回 304,说明页面与上次一致,蜘蛛会直接复用缓存,不会重新解析 HTML,新增的目标链接这一轮也就不会被发现。本文说明 304 的产生条件、容易误判的几种场景,以及该从响应头和日志里检查哪些字段。

常见问题

蜘蛛池入口页返回 304,搜索蜘蛛还会重新读取里面的目标链接吗

很多人在日志里会看到入口页的抓取记录,状态码是 304,响应字节数很小,于是会疑惑:蜘蛛到底有没有读到页面里的目标链接。这篇就围绕 304 这个状态码,说清楚它和 URL 发现之间的关系,以及该检查哪些地方。

304 是怎么产生的

搜索蜘蛛重复抓取一个已经抓过的页面时,往往不是直接要一份完整页面,而是先做条件请求:带上 If-Modified-Since(基于上次响应的 Last-Modified)或 If-None-Match(基于上次响应的 ETag)。服务器比对之后,如果认为内容没有变化,就返回 304 Not Modified,响应体通常是空的。

对服务器来说这是省流量的设计;对爬虫来说,它也确实省下了一次下载。但代价是:蜘蛛手里这份页面,仍然是上一次抓取时的那一份。

为什么这会影响到目标 URL 的发现

搜索蜘蛛发现新链接,靠的是解析 HTML 里真实的 a 标签。如果这次抓取拿到的只是 304,没有新的 HTML,解析这一步就不会重新做一遍。结果就是:

  • 入口页里新增的目标链接,这次抓取不会进入待抓队列;
  • 入口页里已经删掉的目标链接,也不会因为这次抓取而被移除;
  • 从日志上看入口页“被抓了”,但目标 URL 的抓取记录并没有随之增加。

需要说明的是,这不代表链接永远发现不了,只是这一轮抓取没有带来新信息。下一次页面真的有变化并返回 200 时,才有机会被重新解析。

哪些情况会让入口页“该变却返回 304”

正常的 304 是内容真的没变。容易出问题的是下面几类:

  • 入口页是动态生成的,但 ETag 或 Last-Modified 写死了,内容换了校验值却没换;
  • 前面挂了 CDN 或反向代理,缓存规则把更新挡住,蜘蛛拿到的还是旧响应头;
  • 程序里为了让爬虫“少抓几次”而手动返回 304,但页面里的链接列表其实已经更新;
  • 多个入口页共用同一套静态文件,只改了其中一部分,校验值却没有重新生成。

怎么确认问题出在 304 上

可以按顺序排查:

  1. 先记录一次正常抓取的响应头,拿到 Last-Modified 和 ETag 的原值;
  2. 用命令行带上 If-None-Match 或 If-Modified-Since 重新请求,看返回的是 304 还是 200;
  3. 改一处入口页的链接,再重复上一步,如果仍然返回 304,说明校验值没有跟着内容变;
  4. 对照服务器日志里的状态码、响应字节数和抓取时间,确认蜘蛛拿到的是空响应还是完整页面。

更稳妥的处理方式

  • 让校验值跟着内容走:内容变了,ETag 和 Last-Modified 就应该变,不要手工固定;
  • 链接列表有增删时,优先保证这一次返回 200 与完整 HTML,而不是返回 304 省流量;
  • 入口页本身更新频率不高的话,不必为了发现新 URL 频繁改动,新 URL 也可以通过其他入口页或站点地图补上;
  • 别把 304 当成优化手段去刷,返回 304 不等于蜘蛛会顺着缓存里的链接继续抓。
304 的意思是“和上次一样”,它省的是流量,不会帮入口页传递新的链接信息。

最后提醒一点:入口页被抓取、目标 URL 被重新解析,都不等于目标页一定会被收录。抓取、解析、入索引是三个环节,能调整的只是前面这些技术细节,后面的判断仍然在搜索引擎手里。