整理抓取日誌时,经常能看到同一個 URL 在短期内被反复請求,每次都是 200,每次都传輸完整正文。出現這種情况,第一反應往往是“蜘蛛抓得太频繁”,但排查下去常常發現:問题出在服務器没有给爬虫留下“内容没變”的判断依據。
缓存头為什么會進入抓取排查范围
搜尋蜘蛛再次訪問一個 URL 时,通常會带上 If-None-Match 或 If-Modified-Since 請求头,相当于問一句“這個地址和上次相比有没有變化”。如果服務器能明确回答“没變”,返回 304 且不带正文,爬虫就省下了一次完整下载,抓取調度可以把時間用在別的 URL 上。
反過来,如果服務器每次都给不出有效回答,只能返回 200 和整頁 HTML,那么同一批頁面的重复請求就會持續消耗源站带宽和抓取額度。這属于服務器侧的配置問题,不是抓取频率本身的問题。
三類常见的配置失誤
1. ETag 每次請求都變化
部分框架或中間层會把時間戳、随机數、進程 ID 一起參與 ETag 計算,導致同一份内容每次返回的 ETag 都不相同。爬虫带着上一次的 If-None-Match 過来,服務器永遠判定不匹配,只能老老實實返回 200 全量正文。
2. Last-Modified 缺失或時間失真
動態拼接的頁面,Last-Modified 有时取的是“目前渲染時間”,每次請求都在變;也有的站点干脆不輸出這個头。两種情况下,條件請求都失去意义。
3. Cache-Control 一刀切
為了防止内容被错誤缓存,有的站点對所有 HTML 统一加 no-store、no-cache。這類設定會让中間层和抓取侧都放弃复用判断,頁面体积越大,重复下载带来的浪費越明顯。
從日誌里怎么確認
- 統計同一 URL 在一天内的請求次數,以及其中 304 的占比。如果几乎全是 200,說明條件請求基本没生效。
- 检查日誌中是否出現 If-None-Match / If-Modified-Since 字段。如果爬虫压根没带,問题在响應头或中間层;如果带了但结果仍是 200,問题在服務端比對逻辑。
- 對比源站與 CDN 回源记錄的响應头,確認 EDgE 节点没有把 ETag 或 Last-Modified 丢掉。
- 留意平均响應体大小。正文重复传輸的体积,往往比請求次數更能說明浪費程度。
調整顺序建议
- 先固定一套稳定的 ETag 生成規則,建议基于文件指纹或内容摘要,而不是請求時間。
- 為 HTML 輸出可用的 Last-Modified,取值来自内容真實更新時間,而不是渲染時間。
- 把 Cache-Control 按资源類型区分:静態资源可以較長缓存,HTML 用較短 max-age 配合 must-revalidate,避免整站 no-store。
- 確認服務器對 If-None-Match 的比對逻辑能正常返回 304,且 304 响應不带正文。
- 調整後观察一到两周的抓取日誌,看同一 URL 的重复全量下载是否下降、抓取覆盖是否稳定。
需要留意的邊界
- 内容變更时,ETag 與 Last-Modified 必须同步變化。否則爬虫會一直認為頁面没更新,抓到的始终是舊版本。
- 不同搜尋蜘蛛對缓存头的支持程度並不一致,304 只是减少冗余传輸的手段,不能当成通用的抓取节流開關。
- 站点如果使用了多級缓存,任何一层改错都會让 304 失效,改完要在最终對外响應上再確認一遍。
缓存配置的目标不是让爬虫少来,而是让它在每次訪問中拿到准确、有變化的信号。判断标准始终是:内容變了能及时被發現,内容没變不重复传輸。
這類調整通常不會带来立竿见影的抓取量變化,但會体現在長期稳定性上:源站压力更平缓,抓取額度更多流向真正需要更新的頁面。配合 Sitemap 的更新時間维護和内鏈入口检查一起做,效果會更完整。