很多人把抓取異常归到服務器性能上,却忽略了一层:蜘蛛請求某個 URL 时,回给它的往往不是源站刚刚生成的那份 HTML,而是 CDN 或反向代理缓存里的一個副本。缓存配置不同,蜘蛛看到的内容就可能和用戶、和你在浏览器里看到的完全不一样。
蜘蛛拿到的是哪一個版本
缓存本身不是坏事。命中缓存意味着响應更快、源站压力更小,對高频抓取的站点通常是加分項。問题在于缓存键怎么定义:如果只按 URL 缓存,所有請求方共享一份;如果按 URL 加某些請求头缓存,就會出現多份並存的版本,而蜘蛛只拿到其中一份。
Vary 头决定分不分叉
当响應里带 Vary: User-Agent 或 Vary: Accept-Encoding 這類头时,缓存會按對應請求头存多個副本。用戶代理不同、压缩方式不同,都會各存一份。蜘蛛的 UA 往往落在某個不太常见的分组里,如果這個版本的缓存長期没有被刷新,蜘蛛可能反复拿到一份舊内容,而源站早就更新了。
移動版與桌面版的分组
同一個 URL 按设备返回不同 HTML 的站点,要特別留意缓存分组是否覆盖了蜘蛛的 UA。有些配置里只有常见浏览器 UA 才命中「正常」那份缓存,蜘蛛命中的是兜底版本,内容缺字段、缺内鏈,抓取路径自然就断了。
地域节点之間不一致
多节点 CDN 下,各邊缘节点的缓存狀態是各自演進的。蜘蛛從不同出口 IP 過来,拿到的可能是不同节点上的不同版本。排查时如果只在一台机器上測試,很容易得出「内容没問题」的结论。
Cookie、同意彈窗與登入態
另一類分叉来自請求方身份。带 Cookie 的請求通常绕過公共缓存直接回源,不带 Cookie 的請求走缓存。蜘蛛一般不携带你的會话 Cookie,所以它看到的是訪客版本——如果訪客版本被同意彈窗、地域提示遮住正文,或者被重定向到別的地址,抓取到的有效内容就很少。
- 同意彈窗由前端脚本注入时,检查未执行脚本的 HTML 里還剩多少正文;
- 登入墙、付費墙後面是重要内容时,確認蜘蛛能拿到的那一版是否至少包含标题、摘要和可用連結;
- 用 Cookie 做 A/B 測試的站点,注意別把蜘蛛卷進實驗分组。
自查可以從這几個地方入手
- 用蜘蛛的 UA 請求一次 URL,观察响應头里的缓存狀態字段,看清楚是命中、回源還是已過期;
- 把「走缓存」和「直接回源」两次返回的 HTML 並排對比,看正文與内鏈是否一致;
- 查服務器日誌里同一 URL 的返回字节數,如果長期固定不變而頁面早已改版,多半是缓存在供舊版本;
- 检查缓存過期時間,静態资源可以设長,HTML 不宜過長。
缓存策略與抓取稳定性之間
缓存的目标是让响應更快更稳,而不是让蜘蛛一直看舊頁面。對 HTML 這類會變的资源,宁可短缓存加回源校驗,也別设成一個季度不動。
還有一点常被忽略:缓存层返回 5xx 时,蜘蛛收到的是错誤信号,可能触發降低抓取频次。源站偶尔抖動被缓存放大成持續错誤,恢复時間會比想象中長。
抓取這件事,很多时候不是蜘蛛没来,而是它来了、也拿到了响應,只是那份响應和你以為的不一样。把缓存的版本差异理清楚,URL 發現和内鏈路径才有稳定的起点。