蜘蛛请求一个 URL,服务器先返回状态行和响应头,然后才是正文。抓取异常里有一部分跟正文没关系,问题出在头部:内容类型不对、字符编码冲突、或者一条本不该存在的 noindex。正文写得再规整,蜘蛛也可能在解析之前就停下了。
Content-Type 不对,页面可能不算网页
正常网页应该返回 text/html,并带上 charset。常见问题有几类:静态服务器对某些路径返回 application/octet-stream;模板渲染时输出 text/plain;反向代理或 CDN 回源时把头部改写或丢掉。结果是蜘蛛拿到一段二进制或纯文本,正文里的链接也提不出来,URL 发现链条就断在这里。
排查方式很直接:用 curl -I 看第一级响应头,再对比浏览器开发者工具里的实际响应。如果通过 CDN 访问和直接访问源站的头部不一致,问题多半在缓存或回源配置。
编码声明冲突,正文会变成乱码
编码可能出现在两个地方:响应头的 charset,以及 HTML 里的 meta charset。两者不一致时,解析通常更依赖头部声明,正文里的中文会变成乱码,锚文本和链接也可能被拆错。乱码页面本身能被抓,但内容无法理解,链接提取质量下降,后续路径同样受影响。
比较稳的做法是全站统一 UTF-8:服务器、数据库、模板、响应头都对齐。历史页面如果还在用 GBK,至少保证头部声明和实际字节一致。
X-Robots-Tag:比 meta robots 更早生效
meta robots 写在正文里,蜘蛛要先下载并解析 HTML 才能看到;X-Robots-Tag 写在响应头里,读到头部就生效。它的好处是不改页面就能控制索引行为,但也很容易误伤:某次为了压测试环境,在 CDN 或 Nginx 上加了全局 noindex;图片、PDF 目录被加了 nofollow,内链的传递路径就在这些资源处断掉。
更隐蔽的是分环境加头:测试环境加了,配置跟着发布同步到了线上。建议把 X-Robots-Tag 当作和 robots.txt 同级的出口配置,改动时走一次线上验证。
缓存与压缩相关的头
- Vary:写了 Vary: User-Agent 而缓存层按 UA 分版本时,蜘蛛拿到的可能是为其他访问者准备的版本,甚至是一个空壳页。
- Content-Encoding:gzip 或 brotli 声明与实际编码对不上,正文解压失败,蜘蛛看到的是空响应。
- Cache-Control 与过期缓存:页面已经改版,缓存里还是旧版,蜘蛛顺着旧链接继续走,抓到的是已经不存在的路径。
一份自查清单
- 对首页、栏目页、详情页各取一个样本,用 curl -I 看头部,不要只看浏览器。
- 确认 Content-Type 是 text/html,charset 与 meta 声明一致。
- 检查是否存在全局或目录级的 X-Robots-Tag。
- 对比 CDN 与源站返回的头部差异,重点看 Vary 和缓存策略。
- 在服务器日志里交叉验证:状态码、响应字节数、蜘蛛 UA。
抓取路径的第一环,是服务器答应给什么,而不是页面里写了什么。头部是这份答应的一部分,值得在翻正文之前先看一眼。