蜘蛛第一次抓完頁面後,後續重訪並不總是重新下载整份 HTML。如果服務器支持條件請求,蜘蛛會带上 If-Modified-Since 或 If-None-Match,服務器判断内容没變就回一個 304,告诉對方内容還是原来那份。理解這套机制,能解释很多日誌里看起来奇怪的現象。
條件請求的两種凭證
Last-Modified 與 If-Modified-Since 用時間做比較,粒度到秒;ETag 與 If-None-Match 用内容标识做比較,粒度更细。两者可以同时存在,服務器按自己的規則决定用哪個。對抓取来说,關键不是用哪一種,而是這個值要稳定:内容没變时,凭證也不能變。
常见的凭證不稳定
- ETag 由進程 ID、時間戳或随机數生成,每次請求都不同,蜘蛛每次都被判定為新内容。
- Last-Modified 取自動態生成時間,頁面内容没變但時間一直在跳。
- 反向代理或 CDN 改寫了响應头,回源與邊缘的 ETag 不一致。
- WAF 拦掉了 If-None-Match 請求头,服務器每次都返回 200 加完整正文。
這几種情况不會直接導致抓取失敗,但會让蜘蛛做很多無效下载,占用抓取額度,也可能让它誤判頁面的更新频率。
日誌里怎么確認
在訪問日誌中按狀態碼統計即可:304 的數量、對應的 URL,以及同一 URL 上 200 與 304 的交替情况。
- 挑一批内容基本不變的頁面,看它們重訪时是否稳定返回 304。
- 如果全是 200,先看响應头里的 ETag 是否每次都變,再看中間层有没有改寫。
- 如果 304 比例異常高但頁面其實已经改過,检查缓存层是否给出了過期的凭證。
304 表示内容没變,不表示没被抓。它同样是蜘蛛的一次有效訪問,只是没有传輸正文。
和 Sitemap 的 lastmod 配合
Sitemap 里的 lastmod 是给蜘蛛的另一種提示,和 HTTP 层的凭證本质上是同一件事的两種表達。如果 lastmod 寫着昨天更新,而服務器對同一 URL 一直回 304,两個信号就互相矛盾。更新内容後,让 lastmod、Last-Modified、ETag 三者一起變化,是最省事的做法。
几個值得注意的细节
- 304 不传輸正文,蜘蛛拿到的是它缓存里的副本。如果副本已经過期而服務器仍回 304,更新可能被延迟感知。
- 對频繁變動的頁面,比如列表頁和首頁,缓存头不宜設定過長,否則蜘蛛看到的一直是舊版本。
- 對稳定不變的内容頁,允许 304 是好事,既省带宽,也能让蜘蛛把額度留给別的 URL。
- 服務器不稳定时,條件請求可能返回 5xx 或超时,這时要按服務器問题排查,而不是当成缓存配置問题。
小结
把 304 理解成一次確認而不是一次抓取失敗,排查思路就清晰了:先確認凭證是否稳定,再確認中間层有没有改寫响應头,最後看 Sitemap 的 lastmod 和 HTTP 层是否说了同一件事。三處對齐,蜘蛛對頁面更新狀態的判断才不會来回摇摆。