先给结论:多层缓存返回不同版本,通常不是抓取规则本身写错,而是某一层缓存把旧响应留在了自己的存储里,导致同一URL在不同请求路径上拿到不同内容。定位时不要急着改robots.txt或站点地图,应先把“哪一层、哪一个键、哪一种请求头”三者对齐,再决定保留、改写还是退出这层缓存。
多层缓存不一致最容易被误判成抓取规则失效,因为爬虫拿到的版本和浏览器看到的版本不同。此时先固定一个请求指纹:同一URL、同一方法、同一组请求头,分别直连源站、经过第一层缓存、经过第二层缓存各取一次响应。
Content-Length、ETag、Last-Modified、Vary和响应体哈希。这个动作的结果决定下一步:若直连源站与经过缓存返回不同哈希,就进入缓存键与过期策略排查;若三层哈希一致,则应回到抓取规则或渲染环节,而不是继续在缓存里找原因。
同一URL返回不同版本,常见原因是缓存键没有包含真正影响内容的请求头。例如源站根据Accept-Encoding、User-Agent或Cookie返回不同内容,但中间层只按URL做键,就会把A请求的响应交给B请求。
此时保留还是改写,取决于两个条件:
Vary声明与实际行为一致。Vary,否则抓取规则再正确也会拿到错误版本。假设一个场景:源站对移动端和桌面端返回不同canonical,但第一层缓存只按URL缓存。此时爬虫可能拿到移动版canonical,而桌面版页面被判定为重复。验证方法是分别带两种User-Agent请求同一URL,比较响应体中的canonical。若两者不同而缓存层未区分,就属于缓存键缺失,不是抓取规则写错。
缓存返回旧版本,未必是缓存键问题,也可能是过期时间与刷新机制不匹配。源站已更新,但中间层仍按旧的Cache-Control或Expires提供旧响应。此时要区分三种情况:
Age和Date,判断哪一层先过期。可执行的动作是:对同一URL连续请求,记录每层返回的Age变化。如果某一层的Age持续增长且超过源站设定的max-age,说明该层未按预期刷新。这个结果会影响下一步:若该层无法主动刷新,就需要在源站缩短其可缓存时间,或让该层退出缓存链路。
抓取规则控制的是爬虫可以访问哪些路径,缓存控制的是响应如何被复用,两者作用层不同。多层缓存返回不同版本时,优先改缓存层,因为抓取规则改动无法修复已经缓存出去的旧响应。
只有在以下条件同时成立时,才考虑同步调整抓取规则:
需要提醒的是,robots.txt的抓取限制不等于可靠的索引移除,站点地图也不保证收录。即使缓存层已修好,旧版本是否仍出现在索引中,还要看该URL是否被其他信号引用。
单次请求返回一致,不能证明多层缓存已经稳定。至少要在不同时间点、不同入口、不同请求头组合下重复取样,并记录每层响应哈希。若某一层在多次请求中偶发返回旧版本,说明该层存在副本竞争或刷新延迟,而不是抓取规则随机失效。
此时应保留一份对照记录:源站版本、各层版本、时间戳和请求指纹。后续任何改动都以此为基准,才能判断是缓存层被修复,还是问题只是暂时被绕过。最终取舍应基于证据:能对齐缓存键就保留该层,对齐不了就改写或退出,而不是继续在抓取规则上叠加补丁。