蜘蛛每天都會来,但你的頁面大部分時間並没有變化。如果每次訪問都完整返回一遍 HTML,带宽、服務器處理時間和抓取時間就花在了重复内容上。HTTP 的條件請求机制可以把這部分省下来:服務器只回一句“没變”,蜘蛛就不用再下载正文。
條件請求是怎么工作的
蜘蛛第一次抓取某個 URL 时,服務器可以在响應头里给出两個标识之一:ETag(内容的指纹)或 Last-Modified(最後修改時間)。下次再来,蜘蛛會带上 If-None-Match 或 If-Modified-Since,把上次拿到的值發回来。服務器比對後如果認為内容没變,就返回 304 Not Modified,响應里不带正文。
- 200:内容有變化,或服務器無法判断,返回完整頁面。
- 304:内容没變,蜘蛛沿用本地已有的版本。
它對抓取的實际影响
304 不會让蜘蛛“少来”,它仍然會訪問這個 URL,仍然占用一次請求。省下的是這次請求的传輸量,以及服務器重新渲染、序列化頁面的成本。当站点 URL 數量大、更新频率低时,這個差別會累积:服務器响應更轻,蜘蛛在同样的抓取時間预算里走得更顺。
反過来说,如果每個頁面每次都要重新生成、重新传一遍完整 HTML,响應時間和带宽都压在服務器上,抓取高峰期更容易出現超时和 5xx。
几個容易踩的坑
- ETag 每次都變。有些框架用進程 ID、時間戳或文件 inode 生成 ETag,同一個文件两次請求得到两個不同值。蜘蛛每次都判定内容變了,永遠拿 200,條件請求形同虚设,還多了一次無效比對。
- Last-Modified 永遠是目前時間。模板里直接輸出 now(),蜘蛛看到“刚刚修改過”,于是反复重抓。
- 頁面里有易變内容。頁脚時間、随机推荐位、訪問計數器,會让内容指纹每次都不同。這類元素要么改為异步加载,要么在服務器端缓存固定。
- CDN 或反向代理把头剥掉。源站给了 ETag,邊缘节点没有透传,蜘蛛拿到的响應里就没有可用标识。
- 错誤的 304。内容确實更新了却返回 304,蜘蛛會繼續用舊版本,新内容迟迟進不了索引。這類問题排查起来很費時間。
怎么检查和配置
- 用 curl 连續請求同一個 URL 两次,第二次带上第一次返回的 ETag 或 Last-Modified,看是否返回 304。
- 翻服務器日誌,統計全部請求與蜘蛛請求里 304 的占比。占比長期接近零,說明條件請求基本没生效。
- 確認源站配置正确後,再检查 CDN 是否透传 ETag 和 Last-Modified。
- 對确實频繁變動的頁面,不要硬造 304,保持 200 更安全。
條件請求省的是重复传輸,不是抓取次數。把它当成服務器侧的减负手段,而不是用来控制蜘蛛来不来的開關。
和 Sitemap 里的 lastmod 不是一回事
Sitemap 中的 lastmod 是你在清單里声明的時間,属于主動匯报;响應头里的 ETag 與 Last-Modified 是每次請求时的現场比對,属于實时確認。两者可以配合,但不能互相替代:lastmod 寫得不准,最多是判断參考失真;304 判断错了,蜘蛛可能長期停留在舊版本上。
小结一下:把 ETag 和 Last-Modified 配對好,让没變的頁面老實返回 304,让變了的頁面老老實實返回 200,是抓取效率里成本很低、收益却比較稳的一环。