node爬虫之gbk网页中文乱码解决方案

2017年7月31日 评论

之前在用 node 做爬虫时碰到的中文乱码问题一直没有解决,今天整理下备忘。(PS:网上一些解决方案都已经不行了)

中文乱码具体是指用 node 请求 gbk 编码的网页,无法正确获取网页中的中文(需要转码),"gbk" 和 "网页中的中文" 两个条件是缺一不可的。可以获取 utf-8 编码的网页中的中文,也可以获取 gbk 编码网页中的英文数字等。

举个简单的例子。获取  search.51job.com  招聘信息 代码如下:

var http = require('http');
var cheerio = require('cheerio');
var fs = require('fs');

var options = {
  hostname:'search.51job.com',
  port: 80,
  path: '/list/020000,000000,0000,00,9,99,Web%25E5%2589%258D%25E7%25AB%25AF%25E5%25BC%2580%25E5%258F%2591,2,1.html?lang=c&stype=&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&providesalary=99&lonlat=0%2C0&radius=-1&ord_field=0&confirmdate=9&fromType=&dibiaoid=0&address=&line=&specialarea=00&from=&welfare=',
  method: 'GET',
  headers: {
    'Connection' : 'keep-alive',
    'Pragma' : 'no-cache',
    'Cache-Control' : 'no-cache',
    'Upgrade-Insecure-Requests' : '1',
    'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36',
    'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
    'Referer' : 'http://www.51job.com/?from=baidupz',
    'Accept-Language' : 'zh-CN,zh;q=0.8,en;q=0.6'
  }
}

var req = http.request(options, function (res) {
  var arr = [];
  res.on('data', function(chunk) {
    arr.push(chunk);
  });
  res.on('end', function(){
    var buffer = Buffer.concat(arr);
    var html = buffer.toString();
    var jsons = [];
    var $ = cheerio.load(html);
    $('div.el').each(function(i,v) {
      var doc = {
        position: $(v).find('.t1 span a').text().trim(),
        company: $(v).find('.t2 a').text(),
        region: $(v).find('.t3').text(),
        salary: $(v).find('.t4').text(),
        time: $(v).find('t5').text()
      }
      jsons.push(doc);
    })
    fs.writeFile('./data.json', JSON.stringify(jsons),function(err) {
      if(err) {
        throw err;
      }
      console.log('ok');
    })
  });
});

req.on('error', function(err) {
  console.log(err);
})

req.end();

得到了乱码,如下:

������Ӱ

如何获取正确的中文呢?

直接用 iconv-lite 模块进行转码。

iconv-lite 是一个进行编码转换的模块(node 默认编码 utf-8)。需要 decode 的编码必须是 Buffer类型。

var http = require('http');
var cheerio = require('cheerio');
var iconv = require('iconv-lite'); 
var fs = require('fs');

var options = {
  hostname:'search.51job.com',
  port: 80,
  path: '/list/020000,000000,0000,00,9,99,Web%25E5%2589%258D%25E7%25AB%25AF%25E5%25BC%2580%25E5%258F%2591,2,1.html?lang=c&stype=&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&providesalary=99&lonlat=0%2C0&radius=-1&ord_field=0&confirmdate=9&fromType=&dibiaoid=0&address=&line=&specialarea=00&from=&welfare=',
  method: 'GET',
  headers: {
    'Connection' : 'keep-alive',
    'Pragma' : 'no-cache',
    'Cache-Control' : 'no-cache',
    'Upgrade-Insecure-Requests' : '1',
    'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36',
    'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
    'Referer' : 'http://www.51job.com/?from=baidupz',
    'Accept-Language' : 'zh-CN,zh;q=0.8,en;q=0.6'
  }
}

var req = http.request(options, function (res) {
  var arr = [];
  res.on('data', function(chunk) {
    arr.push(chunk);
  });
  res.on('end', function(){
    var html = iconv.decode(Buffer.concat(arr), 'gbk');
    var jsons = [];
    var $ = cheerio.load(html, {decodeEntities: false});
    $('div.el').each(function(i,v) {
      var doc = {
        position: $(v).find('.t1 span a').text().trim(),
        company: $(v).find('.t2 a').text(),
        region: $(v).find('.t3').text(),
        salary: $(v).find('.t4').text(),
        time: $(v).find('t5').text()
      }
      jsons.push(doc);
    })
    fs.writeFile('./data.json', JSON.stringify(jsons),function(err) {
      if(err) {
        throw err;
      }
      console.log('ok');
    })
  });
});

req.on('error', function(err) {
  console.log(err);
})

req.end();
  • 用 iconv 进行 decode 传入的参数必须是 Buffer。

    encoding - Encoding to be used on setEncoding of response data. If null, the body is returned as a Buffer. Anything else (including the default value of undefined) will be passed as the encoding parameter to toString() (meaning this is effectively utf8 by default). (Note: if you expect binary data, you should set encoding: null.)

iconv-lite 模块能配合 http 模块以及 request 模块使用,却不能直接和 superAgent 模块使用。因为 superAgent 是以 utf8 去取数据,然后再用 iconv 转也是不行的。页面是 gbk 编码的,sres.text 已经是 decode 过了的结果,也就是说它已经被转换成 utf8 了,再转换成 buffer 出来的结果必须是不正确的。

weinxin
我的微信
爱生活、爱学习的小伙伴可以通过扫一扫二维码添加我的个人微信一起交流!
利用n管理node版本,轻松切换node Node.js

利用n管理node版本,轻松切换node

前言 这段时间,一直都是用node的稳定版本,最近因为工作需要,需要用到其他node版本,Google搜了一下,有很好的一个解决方案,选择node版本管理工具,轻松切换node。有两个很好的node版...
正确的安装和使用nvm(mac) Node.js

正确的安装和使用nvm(mac)

前言 目前主流的node版本管理工具有两种,nvm和n。两者差异挺大的,具体分析可以参考一下淘宝FED团队的一篇文章: 管理 node 版本,选择 nvm 还是 n? 总的来说,nvm有点类似于 Py...
nodejs 请求数据不完整问题解决 Node.js

nodejs 请求数据不完整问题解决

今天用nodejs请求天气数据时遇到使用JSON.parse()解析数据时始终报错的问题,仔细调试后才发现获取到的json字符串莫名的丢掉了一部分; const https = require('ht...
匿名

发表评论

匿名网友