搜尋抓取

蜘蛛抓到的頁面和用戶看到的不一样:缓存层带来的差异

站点接入 CDN 或反向代理後,蜘蛛抓到的頁面有时和用戶看到的不一致:可能是邊缘缓存里的舊副本,也可能是一張驗證頁。本文從請求鏈路、缓存头、條件請求和防護規則几個角度,說明怎么定位這種差异,以及哪些配置能让抓取路径更稳定。

搜尋抓取

蜘蛛抓到的頁面和用戶看到的不一样:缓存层带来的差异

很多站点接入 CDN 或反向代理之後,會碰到一個不太直观的問题:自己用浏览器看頁面是新的,蜘蛛抓到的却是舊内容;或者用戶在頁面上看到的内容正常,蜘蛛拿回来的却是一張驗證頁。這類差异通常不發生在内容本身,而在請求经過的那几层缓存與防護上。

蜘蛛的一次請求要经過哪些环节

把鏈路拆開看,問题會清楚很多:

  1. 蜘蛛解析域名,向 DNS 查询得到地址,這一步通常返回的是 CDN 邊缘节点的 IP;
  2. 邊缘节点检查本地是否有可用的缓存副本,命中就直接返回,不回源站;
  3. 未命中或副本已過期时,邊缘节点回源站拉取;
  4. 源站或中間可能還有一层 WAF、负载均衡或頁面缓存插件,它們同样能改寫返回内容。

蜘蛛看到的 HTML,是這條鏈路上最後一次寫入的结果。任何一环给了舊副本或替換了响應,蜘蛛拿到的就和你本机刷新看到的不同。

缓存命中时,蜘蛛拿到的是哪一份副本

HTTP 缓存头决定邊缘节点把一份 HTML 保留多久。Cache-Control 的 max-age 與 s-maxage 是最常被混用的两個指令:前者對浏览器和共享缓存都生效,後者只针對 CDN 這類共享缓存。如果给 HTML 设了很長的 s-maxage,頁面更新後蜘蛛再抓,很可能還是更新前的版本。

stale-while-revalidate 也值得留意。它允许邊缘节点在副本過期後先返回舊内容,同时後台回源刷新。對静態资源没什么問题,對经常變動的詳情頁、活動頁就可能让蜘蛛连續几天抓到舊版。

反過来,如果响應里带 Age 头,可以直接看出這份副本已经在邊缘停留了多久。排查时這個字段比猜测有用得多。

條件請求與 304 的關系

蜘蛛再次抓取同一 URL 时,常會带上 If-None-Match 或 If-Modified-Since。如果服務端返回 304,蜘蛛就沿用本地已有版本,不重新解析正文。這本身是正常且高效的行為,但前提是 ETag 與 Last-Modified 能准确反映内容變化。

如果 ETag 是按机器、進程或時間戳生成的,每次回源都不一样,會出現两種情况:一邊是缓存無法复用、回源量上升;另一邊是内容其實没變,蜘蛛却每次都被当成新内容重新處理。多數情况下這不會直接造成收錄問题,但會让抓取效率變差。

防護規則把蜘蛛当成普通流量

比缓存更棘手的是拦截。WAF、UA 黑名單、频率限制、JavaScript 挑战都可能作用在爬虫請求上。常见後果有三種:

  • 返回 403 或 503,蜘蛛這次抓取失敗,稍後可能重试,也可能降低對该路径的訪問频率;
  • 返回挑战頁,但狀態碼是 200。這时代碼會被当作頁面正文處理,等于把一張空壳頁当成了真實内容;
  • 返回精简過的 HTML,比如只给一部分内容,蜘蛛看到的頁面结构和你预期的不同。

需要說明的是,让蜘蛛 UA 绕過某些規則只是一種技術選擇,它並不等于對抓取行為不做任何约束,也不意味着一放行就會被正常收錄。

怎么確認差异出在哪一层

  • 用命令行請求首頁與重点頁面,观察响應头里的 Cache-Control、Age、X-Cache 一類字段;
  • 對比源站訪問日誌:蜘蛛 UA 到達时返回的狀態碼、响應体大小、耗时;
  • 连續抓两次同一 URL,看第二次是否命中缓存、返回内容是否變化;
  • 如果頁面内容依赖登入態或地区,確認這些分支是否影响蜘蛛看到的版本。

几個可以落地的調整

  • HTML 不要設定過長的强缓存,需要長期缓存的是图片、样式、脚本這類带指纹的静態资源;
  • 内容更新後主動刷新相關 URL 的邊缘缓存,而不是等自然過期;
  • 保持 ETag 稳定,让相同的正文對應相同的标识;
  • 挑战頁、限流頁尽量返回明确的 503 並配合 Retry-After,避免用 200 包裹空内容;
  • 把蜘蛛的訪問單獨打点,一旦回源率或異常狀態碼上升,能第一時間看见。
缓存與防護本身都是必要的,問题往往不在這類组件是否存在,而在于蜘蛛請求经過它們时拿到的到底是不是你希望它讀到的那份頁面。把這一层的返回内容固定下来,抓取路径才谈得上稳定。