搜尋抓取

Last-Modified 與 ETag:蜘蛛回訪时怎么判断頁面有没有變

蜘蛛回訪頁面时,條件請求决定了它要不要重新下载整頁。Last-Modified 和 ETag 這两個头部如果設定得可靠,可以帮助减少重复传輸,把抓取节奏留给真正更新的 URL;如果設定得随意,反而會让蜘蛛反复回訪。本文梳理两者的使用要点、常见坑和自查方法。

搜尋抓取

Last-Modified 與 ETag:蜘蛛回訪时怎么判断頁面有没有變

蜘蛛回訪一個頁面时,並不一定會把整頁重新下载一遍。很多爬虫會先發條件請求,問服務器一句:這個頁面從上次抓取到現在,有没有變過?服務器如果回答“没變”,蜘蛛就只拿到一個很短的响應,不必重复拉取正文。這個過程依赖两個常见的 HTTP 头部:Last-Modified 和 ETag。

條件請求:蜘蛛先問“變了吗”

第一次抓取时,服務器在响應里给出 Last-Modified 或 ETag。蜘蛛把這组值记下来。下次回訪时,它會在請求头里带上 If-Modified-Since 或 If-None-Match,把上次拿到的值回传给服務器。

  • If-Modified-Since 對應 Last-Modified,用時間做比較。
  • If-None-Match 對應 ETag,用标识符做比較。
  • 服務器判断内容没有變化,返回 304 Not Modified,不返回正文。
  • 如果内容變了,返回 200,重新给出完整頁面和新的驗證值。

對蜘蛛来说,304 的主要意义是省下重复传輸,把有限的抓取节奏留给新 URL 和真正更新的舊 URL。它本身不是排名信号,也不代表頁面會被收錄。

Last-Modified 要真實,不要“永遠新鲜”

Last-Modified 最好来自内容真正發生變更的時間。常见問题是動態頁面在每次請求时都輸出目前時間,蜘蛛每次回訪都會看到“刚刚更新”,于是反复抓取同一個没有變化的頁面。另一種情况是時間戳来自模板渲染時間或缓存生成時間,和内容實际修改時間對不上,也會让條件請求失去參考價值。

如果站点有發布流程,可以把 Last-Modified 和發布時間、編輯時間绑定,並且在模板层保持稳定。不要因為用戶评论數、阅讀數這類频繁變動但正文没變的因素,就贸然刷新整個頁面的時間戳。

ETag 不要用随机值或進程标识

ETag 可以理解成服務器给某個版本内容贴的标簽。强 ETag 要求字节級一致,弱 ETag 允许语义相同但字节略有差异。問题往往出在生成方式上:有些程序預設用進程 ID、内存地址或目前時間拼 ETag,结果每次請求都不一样。蜘蛛带着 If-None-Match 回来,服務器永遠匹配不上,只能一直返回 200。

更稳妥的做法是基于内容做哈希,或者干脆只保留 Last-Modified,不輸出 ETag。两者同时存在时,蜘蛛會優先使用 ETag。如果 ETag 不可靠,反而會覆盖掉本来可用的時間校驗。

304 對抓取节奏的實际影响

  • 减少响應体积,對带宽和源站负载都有帮助。
  • 让蜘蛛用更少的成本確認舊頁面狀態,腾出节奏去發現新 URL。
  • 不能替代内鏈结构和 Sitemap,頁面如果長期没有入口,條件請求也帮不上忙。
  • 304 仍然要建立连接、等待服務器响應,源站响應慢,蜘蛛一样會被拖住。
304 省的是重复下载,不是抓取動作本身。服務器耗时偏高时,條件請求並不會让抓取节奏自動變快。

中間层可能改寫头部

CDN、反向代理、WAF 和安全插件都可能删掉、改寫或统一化 Last-Modified 和 ETag。常见表現是:回源請求能看到正确的头部,但邊缘节点返回给蜘蛛的是另一套值;或者不同节点返回的 ETag 不一致。蜘蛛在不同時間、不同节点拿到的标识不稳定,條件請求就容易失效。检查时最好分別看回源响應和邊缘响應。

怎么自查

  1. 用 curl -I 连續請求同一個 URL,观察 Last-Modified 和 ETag 是否稳定。
  2. 带上 If-None-Match 或 If-Modified-Since 再請求一次,確認是否返回 304。
  3. 在服務器日誌里統計 304 與 200 的比例,看回訪是否大量重复拉取正文。
  4. 核對内容更新時間與發布流程,確認头部時間不是渲染時間或缓存時間。
  5. 如果使用了 CDN,分別驗證回源和邊缘的响應头。

小结

Last-Modified 和 ETag 是蜘蛛回訪时的重要參考,但它們的價值来自稳定和真實。把這两個头部当作站点运营的一部分,和發布流程、缓存策略一起维護,比频繁調整抓取策略更實际。條件請求做對了,蜘蛛可以把更多精力放在新 URL 和内容确實變化的頁面上。