浏览器能容忍的,蜘蛛不一定能
同一个地址,你在浏览器里看着正常,蜘蛛拿到的却可能是空白、乱码或者半截内容。原因往往不在 HTML 本身,而在传输和编码这两层:响应头怎么说、内容实际怎么压、字符集怎么声明。浏览器有大量容错和猜测机制,蜘蛛的解析流程更依赖声明,一旦声明和实际对不上,它就按自己的规则处理,结果通常不是你想要的。
Content-Encoding 与实际内容对不上
用 gzip 或 Brotli 压缩页面是常规操作,但前提是声明和实际一致。常见的三类问题:
- 响应头写了 Content-Encoding: gzip,返回的却是未压缩内容,或者反过来。解压失败会被记成一次抓取错误。
- 源站和 CDN 各压一次,形成双重压缩。蜘蛛只解一层,拿到的是压缩数据的二进制流,页面自然是乱码。
- 压缩后的长度与 Content-Length 不一致,连接被提前截断,正文只到一半。
这几类问题在浏览器里往往感觉不到,因为浏览器会尝试多种解码方式;蜘蛛按声明解码失败后,一般不会反复试探。
怎么快速确认
用命令行看头部最直接:curl -sI 加上地址,观察 Content-Type、Content-Encoding、Content-Length 三项是否互相矛盾。再用 curl --compressed 取一次完整响应,对比压缩前后的字节数。如果解压后的大小异常小,基本可以定位问题出在压缩链路。
字符集:三条声明渠道,只有一条说了算
一个页面的字符集可能出现在三个地方:HTTP 响应头的 Content-Type、HTML 里的 meta charset、以及文件自身的实际编码。它们的优先级通常是响应头最高,meta 次之,文件实际编码只是事实。
- 响应头声明 charset=utf-8,实际文件是 GBK,蜘蛛按 utf-8 解码,中文整段变成乱码。
- 响应头没写 charset,meta 声明 utf-8,但文件带 BOM 或是 GBK,解码同样可能出错。
- 两边都没写,蜘蛛只能靠统计猜测,长页面里中文比例高时猜错的概率并不低。
乱码之后会发生什么
很多人以为只是显示不好看,实际上影响会一路传导下去:
- 链接解析:href 里带中文参数或中文路径时,解码错误会把链接指向不存在的地址,蜘蛛顺着走下去就是一片 404。
- 正文提取:正文变成乱码或空白,页面质量判断会明显偏低。
- 元信息:title、description 错乱,展示结果和你的预期完全不同。
- 整页判定:解码失败严重时,蜘蛛可能直接把这页当成空内容,反复抓取也拿不到有效信息。
BOM 和不可见字符
文件开头多出的 BOM、编辑器留下的零宽字符、模板拼接时混入的控制字符,都会占用正文开头的位置。有些程序在处理时把它们当正文输出,页面开头于是出现奇怪符号,进一步干扰解析。
一份可落地的排查清单
- 检查响应头:curl -sI 看 Content-Type、Content-Encoding、Content-Length 三项是否自洽。
- 检查实际编码:把响应正文保存成文件,用编码检测工具确认是不是声明的那个字符集。
- 检查压缩链路:临时关掉 CDN 压缩,只留源站压缩,观察抓取是否恢复正常。
- 检查声明一致性:响应头、meta、文件编码三者统一,避免任何一条成为例外。
- 检查日志:抓取失败率、空内容页面数量是否集中在某几个模板或某次发布之后。
把问题挡在蜘蛛进来之前
传输和编码是抓取链路里最底层的一环,出错时上层的内链优化、Sitemap 提交都无从发挥。把响应头、压缩方式、字符集三件事固定成上线检查的一部分,比事后从日志里逐个找原因省事得多。对蜘蛛来说,一份能正确解压、按声明解码的响应,是后面所有工作的前提。
提醒一句:编码问题不会因为你看不到就消失,它只是换了一种形式出现在抓取日志里。