蜘蛛再次訪問一個已经抓過的 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 时的几個常见坑
- 返回 304 却带正文:部分框架把狀態碼和内容一起輸出,不同中間层處理方式不一致。
- 中間层改寫:CDN、WAF、反向代理可能剥离或重寫 ETag,導致下次校驗對不上。
- 動態 ETag:值每次都變,條件請求永遠不命中。
- Last-Modified 不一致:同一份内容在不同节点返回不同時間,判断标准就乱了。
- 忽略條件請求:把带條件头的請求当普通請求處理,直接回完整頁面。
對抓取效率和服務器压力的實际影响
對一個頁面數量較多、内容長期稳定的站点,條件請求能把重复抓取中的传輸量压下来。對蜘蛛来说,省下的是传輸和解析成本,可能让同一時間窗里多走几個 URL;對服務器来说,省下的是带宽和一部分渲染開销。
但要注意:304 並不會让蜘蛛“不来抓”。它仍然是抓取配額里的一次訪問,真正的收益在传輸和解析环节,而不是“少记一次訪問”。把它当成提高效率的優化手段更合适,不要指望靠它解决抓取量不足的問题。
什么情况下不太值得投入
内容更新频繁的頁面,比如资讯流、库存和價格頁,條件請求的命中率本来就低,不必為了命中率强行设計缓存策略。反過来,文档頁、帮助頁、老文章、静態资源這類長期不變的 URL,是比較值得把條件請求做對的地方。
自查清單
- 用 curl -I 查看首次响應是否带有 ETag 或 Last-Modified。
- 带 If-None-Match 再請求一次,確認返回 304 且没有正文。
- 對比 CDN 邊缘节点與回源返回的头部是否一致。
- 確認 ETag 里不含随机數、時間戳、進程 ID 這類每次都變的值。
- 確認 Last-Modified 對應内容真實更新時間,而不是“目前時間”。
- 從服務器日誌里看 304 的比例,判断條件請求是否真的生效。
條件請求只是抓取效率鏈條上的一环,它和 Sitemap、内鏈结构、服務器稳定性一起,决定蜘蛛把時間花在哪里。先把長期稳定的頁面做成“可协商”的,再考虑更新频繁的部分,顺序上會轻松很多。