常见問题

蜘蛛池入口頁返回 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 被重新解析,都不等于目标頁一定會被收錄。抓取、解析、入索引是三個环节,能調整的只是前面這些技術细节,後面的判断仍然在搜尋引擎手里。