搜尋抓取

304 與條件請求:蜘蛛重复抓取时怎样只传狀態不传正文

蜘蛛第二次訪問同一個 URL 时,如果服務器支持條件請求,可以用 ETag 或 Last-Modified 判断内容有没有變,没變就只回一個 304。本文說明這套机制怎么走、服務器返回 304 时常踩的坑,以及它對抓取效率和服務器压力的實际影响。

搜尋抓取

304 與條件請求:蜘蛛重复抓取时怎样只传狀態不传正文

蜘蛛再次訪問一個已经抓過的 URL 时,並不一定需要把整頁内容重新下载一遍。如果服務器支持條件請求,蜘蛛可以带着上一次记錄的校驗信息,問一句“這個頁面變了吗”,没變就只回一個 304。這一步看着是技術细节,却直接關系到抓取预算和服務器带宽怎么花。

一次重复抓取里發生了什么

蜘蛛第一次抓到頁面时,响應头里可能带有 ETag 或 Last-Modified,它會把這两個值连同 URL 一起记下来。下次再来时,請求头里就會出現對應的條件字段。

  • If-None-Match:携带上次记錄的 ETag 值。
  • If-Modified-Since:携带上次记錄的 Last-Modified 時間。

服務器判断内容没變,就返回 304 Not Modified,並且不带正文。蜘蛛拿到“没變”這個结论,繼續使用已有副本,同时更新抓取時間。省下的是一次完整的正文传輸。

ETag 與 Last-Modified 各自的特点

  • ETag 更贴近内容本身,能反映细微改動,但生成規則由服務器决定,站点之間不统一。
  • 弱 ETag(带 W/ 前缀)表示“语义上等價”,不保證逐字节相同。
  • Last-Modified 精度到秒,容易被模板渲染時間、时区、動態變量干扰,判断會偏粗。
  • 两者同时存在时,服務器可以按自己的優先級判断,通常 ETag 更被優先采用。
如果每次請求都生成一個新的 ETag,比如基于随机數或請求時間,等于告诉蜘蛛“每次都變了”,反而會引發更多完整抓取,效果和预期完全相反。

服務器返回 304 时的几個常见坑

  1. 返回 304 却带正文:部分框架把狀態碼和内容一起輸出,不同中間层處理方式不一致。
  2. 中間层改寫:CDN、WAF、反向代理可能剥离或重寫 ETag,導致下次校驗對不上。
  3. 動態 ETag:值每次都變,條件請求永遠不命中。
  4. Last-Modified 不一致:同一份内容在不同节点返回不同時間,判断标准就乱了。
  5. 忽略條件請求:把带條件头的請求当普通請求處理,直接回完整頁面。

對抓取效率和服務器压力的實际影响

對一個頁面數量較多、内容長期稳定的站点,條件請求能把重复抓取中的传輸量压下来。對蜘蛛来说,省下的是传輸和解析成本,可能让同一時間窗里多走几個 URL;對服務器来说,省下的是带宽和一部分渲染開销。

但要注意:304 並不會让蜘蛛“不来抓”。它仍然是抓取配額里的一次訪問,真正的收益在传輸和解析环节,而不是“少记一次訪問”。把它当成提高效率的優化手段更合适,不要指望靠它解决抓取量不足的問题。

什么情况下不太值得投入

内容更新频繁的頁面,比如资讯流、库存和價格頁,條件請求的命中率本来就低,不必為了命中率强行设計缓存策略。反過来,文档頁、帮助頁、老文章、静態资源這類長期不變的 URL,是比較值得把條件請求做對的地方。

自查清單

  1. 用 curl -I 查看首次响應是否带有 ETag 或 Last-Modified。
  2. 带 If-None-Match 再請求一次,確認返回 304 且没有正文。
  3. 對比 CDN 邊缘节点與回源返回的头部是否一致。
  4. 確認 ETag 里不含随机數、時間戳、進程 ID 這類每次都變的值。
  5. 確認 Last-Modified 對應内容真實更新時間,而不是“目前時間”。
  6. 從服務器日誌里看 304 的比例,判断條件請求是否真的生效。

條件請求只是抓取效率鏈條上的一环,它和 Sitemap、内鏈结构、服務器稳定性一起,决定蜘蛛把時間花在哪里。先把長期稳定的頁面做成“可协商”的,再考虑更新频繁的部分,顺序上會轻松很多。