你看到的页面,和蜘蛛拿到的可能不是同一份
本地打开正常、浏览器里内容是最新的,并不代表蜘蛛抓到的也是这样。请求从蜘蛛出发到你的源站,中间可能经过 CDN、反向代理、负载均衡、页面缓存插件等多层。任何一层返回了缓存副本,蜘蛛拿到的就是那一份,而不是源站当前的内容。
抓取层面的问题往往不是“抓不到”,而是“抓到的是旧的或错的”。下面几种情况在排查日志时比较常见。
缓存命中:蜘蛛拿到的是几天前的副本
如果页面设置了较长的缓存时间,而更新时没有做主动刷新,缓存节点会继续把旧 HTML 发给所有请求方,包括蜘蛛。表现是:你改了标题、正文或内链,蜘蛛再次抓取到的内容仍停留在旧版本。
更麻烦的是链接结构。新增的内链如果只出现在源站的新版本里,蜘蛛从缓存拿到的页面里根本看不到这条链接,URL 发现自然就慢了一拍。
边缘节点不一致:同一 URL,不同机房返回不同内容
多节点 CDN 在回源失败、预热未完成或缓存过期时间不一致时,可能出现“A 节点是新版,B 节点是旧版”。蜘蛛的出口 IP 分布在多地,抓取结果就会时好时坏,日志里表现为同一 URL 反复抓取、内容快照来回变化。
如果站点做了按地区返回不同内容(多语言、多货币),但没有用 Vary 或独立 URL 区分,缓存层会把某个地区的版本发给所有节点,蜘蛛看到的可能不是主版本。
被缓存的状态码:404 和 301 的残留
状态码同样会被缓存。上线过程中临时出现的 404、维护页的 503、迁移时的 301,如果被缓存层记住了较长时间,即使源站已经恢复正常,蜘蛛仍然会持续拿到这个响应。
- 临时 404 被缓存:蜘蛛把正常页面当成死链,已发现的 URL 会被降频。
- 301 被缓存:跳转目标改了,蜘蛛还在按旧地址走。
- 503 被缓存:蜘蛛判断站点不可用,整体抓取节奏放慢。
因此状态码的缓存时间通常要设得比页面内容短,尤其是错误响应。
几个和抓取直接相关的响应头
- Cache-Control:决定内容在中间层停留多久。max-age 太长,更新后蜘蛛也会拿到旧版。
- Vary:按 UA、Accept-Encoding 等维度区分缓存。忽略它,不同客户端会互相串味。
- ETag / Last-Modified:支持条件请求,蜘蛛可以用 If-Modified-Since 只取变更部分,减少无谓传输。
- Age / X-Cache:用来判断这次响应是命中缓存还是回源,排查时很有用。
用爬虫 UA 验证,而不是只看浏览器
浏览器请求通常带 Cookie、走不同的缓存策略,看到的结果不能代表抓取结果。排查时按下面的顺序来:
- 用蜘蛛的 User-Agent 请求目标 URL,记录状态码、响应头和正文摘要。
- 对比源站直连和走 CDN 的响应,看时间戳、内容长度是否一致。
- 换个出口 IP 或指定不同边缘节点再请求一次,确认节点之间是否一致。
- 查看响应头里的 Age、X-Cache 等标记,确认是否命中缓存。
- 更新内容后主动刷新缓存,再重复第一步,确认蜘蛛能拿到新版。
- 对照服务器日志里的蜘蛛请求记录,确认它实际拿到的状态码分布。
哪些内容适合让缓存对蜘蛛“让路”
不是所有页面都需要对蜘蛛穿透缓存。图片、样式、脚本这类静态资源,长缓存基本没有副作用;变化频繁的列表页、首页、详情页,缓存时间要短一些,或者更新时主动刷新。robots.txt 和 sitemap 文件建议用较短的缓存时间,规则变更后蜘蛛能较快读到新版本。
缓存本身不是抓取问题,缓存和内容更新不同步才是。把“更新后多久缓存刷新”和“蜘蛛多久再来看一次”当成两件独立的事来管,排查会清楚很多。
小结:抓取结果受中间层影响,而中间层往往是运维配置,不在内容编辑的视野里。出现“内容改了但抓取还是旧的”时,先确认蜘蛛实际拿到的响应,再回过头看缓存策略和状态码缓存,比反复调整内链更有效。