做入口页的时候,多数人把注意力放在链接结构、内链拓扑和内容量上,很少回头检查最底层的一件事:蜘蛛拿到的字节,究竟被解释成了什么文字。这一步出错,后面所有判断都建立在错误输入上。
蜘蛛解码一个页面时看什么
抓取请求返回的是字节流,蜘蛛需要先确定字符集才能把字节还原成文本。它一般按这个顺序找依据:
- HTTP 响应头里的 Content-Type,例如 text/html 后面跟的 charset 参数,优先级最高;
- 如果响应头没有 charset,再读 HTML 文档头部的 meta charset 声明;
- 文件开头的 BOM 也会参与判断。
这几个来源只要互相打架,解析结果就会偏离你的预期。常见的是页面头声明 utf-8,实际字节却是 GBK,中文直接变成问号或方块。
三类高频的编码误配
声明与实际字节不一致
典型场景是数据库连接用了 UTF-8,模板输出时又经过一次转码,或者服务器默认字符集是旧的本地编码,而页面头写死 utf-8。蜘蛛按 utf-8 解码 GBK 字节,会得到一串无意义的字符;反过来按 GBK 解 utf-8 字节,则容易出现连续乱码。
完全没有 charset 声明
部分老配置只返回 text/html,不带任何 charset,meta 里也没有写。这时蜘蛛只能靠启发式规则猜。纯英文页面猜错概率低,中英混排、夹杂符号的页面就不好说了。这不是蜘蛛的能力问题,而是你把不确定性主动留给了它。
按字节截取生成的半个汉字
用按字节截断的函数处理摘要或标题,一个汉字被砍成两三个字节里的前一个,就产生了非法字节序列。解析器遇到非法序列时,往往会丢掉后面一整段,而不是只丢一个字。表现就是入口页的描述文字只剩前半句。
Content-Type 本身写错会怎样
除了 charset,主类型写错同样有影响:
- HTML 页面被返回成 text/plain,蜘蛛可能按纯文本处理,页面里的链接不再被当作链接;
- 返回 application/octet-stream,容易被当成下载文件,而不是可解析的文档;
- 返回 text/html 但内容其实是接口返回的 JSON,正文就变成一段无法理解的字符堆。
还有一种情况是入口页既做展示又做跳转,200 与 3xx 的语义混在一起,编码问题叠加状态码问题,排查难度会翻倍。
建议的排查顺序
- 用命令行工具只看响应头,确认 Content-Type 里到底有没有 charset,写的是什么;
- 把原始响应保存成文件,用编码识别工具或十六进制编辑器确认真实字节编码,不要只看浏览器渲染结果;
- 核对 HTML 头部 meta 声明,以及文件是否带 BOM;
- 核对数据库连接字符集、模板输出字符集、服务器默认字符集是否一致;
- 修复后重新抓取几个不同类型的页面抽查,尤其是含中文标题和摘要的页面。
浏览器有很强的编码猜测和容错能力,你在屏幕上看到正常,不代表蜘蛛读到的是同一份文本。以原始响应为准,是这类问题的基本习惯。
静态资源也别落下
CSS 与 JS 文件如果编码声明错误,可能触发解析失败,影响渲染型抓取对页面的理解。多数搜索引擎的处理有一定容错,但入口页本来就靠结构清晰来降低抓取成本,没必要在这里多引入一个变量。
给入口页的几条实用建议
- 全站统一 UTF-8,包括数据库、模板、服务器默认字符集,避免中途转码;
- 在 HTTP 响应头里显式声明 charset,不要只依赖 meta;
- 处理中文时使用多字节安全的截取函数,不要按字节切分;
- 配置文件以 UTF-8 无 BOM 保存,减少 BOM 与声明冲突;
- 批量接入新入口页之前,做一次统一的编码与响应头检查。
编码问题通常不是影响蜘蛛是否来访的主要因素,但它会改变蜘蛛读到的内容。输入错了,后面关于相关性、重复度、链接的判断都会跟着偏移。
这类问题的好处是排查成本低、修复一次就长期有效。把它放进入口页的上线检查清单,比事后从抓取日志里反向推测要省事得多。