现象

写 Node 爬虫时,部分站点中文变成「锟斤拷」或乱码。原因通常不是 cheerio 坏了,而是:页面不是 UTF-8,却被按 UTF-8 解成了字符串。

国内老站仍常见 GBK / GB2312。浏览器能正常显示,是因为 HTTP 头或 <meta charset> 声明了编码;你的脚本若默认 UTF-8,就会错。

怎么确认编码

  1. DevTools → Network → 文档响应头 Content-Type: text/html; charset=gbk
  2. 查看源码 <meta charset="gbk"> / gb2312
  3. 仍不确定时,可用 chardet 类库做探测(不要 100% 盲信)

正确做法:先拿字节,再解码

request(或其它 HTTP 库)若自动把 body 转成字符串,会按错误编码损坏数据。应:

  1. 禁用自动字符串解码,拿到 Buffer
  2. iconv-lite 按真实编码 decode
const request = require('request');
const cheerio = require('cheerio');
const iconv = require('iconv-lite');

request(
  {
    url: 'https://example.com/',
    encoding: null, // 关键:body 为 Buffer
  },
  (err, res, body) => {
    if (err) throw err;

    // 按站点实际编码修改
    const html = iconv.decode(body, 'gbk');
    const $ = cheerio.load(html);
    console.log($('head title').text());
  }
);

注意旧笔记里的笔误:encodeing 应为 encodingcheerio 不要写成 request('cheerio')

现代写法(axios / fetch)

const axios = require('axios');
const iconv = require('iconv-lite');

const res = await axios.get(url, { responseType: 'arraybuffer' });
const html = iconv.decode(Buffer.from(res.data), 'gbk');

常见坑

说明
toString('utf8') 再转信息已丢,无法救
编码写死 gbk多站点要按响应头切换
忽略压缩确保先解 gzip 再解码
合规爬虫需遵守 robots/授权与频率限制

小结

乱码问题的本质是 字节序列被用错字符集解释。爬虫链路固定为:Buffer → 判定 charset → iconv-lite → 再 parse DOM