node爬蟲之gbk網頁中文亂碼解決方案


之前在用 node 做爬蟲時碰到的中文亂碼問題一直沒有解決,今天整理下備忘。(PS:網上一些解決方案都已經不行了)

中文亂碼具體是指用 node 請求 gbk 編碼的網頁,無法正確獲取網頁中的中文(需要轉碼),"gbk" 和 "網頁中的中文" 兩個條件是缺一不可的。可以獲取 utf-8 編碼的網頁中的中文,也可以獲取 gbk 編碼網頁中的英文數字等。

舉個簡單的例子。獲取 http://acm.hdu.edu.cn/statistic.php?pid=1000 排名第一的答案的 username,是為 "極光炫影"。刷刷刷寫下如下代碼:

var cheerio = require('cheerio')
  , superagent = require('superagent')
  , express = require('express');

var url = 'http://acm.hdu.edu.cn/statistic.php?pid=1000';
var app = express();

app.get('/', function (req, res, next) {

  superagent.get(url)
    .end(function (err, sres) {
      var html = sres.text;
      var $ = cheerio.load(html, {decodeEntities: false});
      var ans = $('.table_text td a').eq(0).html();
      res.send(ans);
    });
  });

app.listen(3000, function () {
  console.log('app is listening at port 3000');
});

得到了亂碼,如下:

������Ӱ

如何獲取正確的中文呢?這里提供幾個解決方案應急(不關心原理,只是為了應急)。

方法一:

使用 superagent-charset 模塊(2016-08-26:如出錯,請使用 0.1.1 版本,安裝命令 npm install superagent-charset@0.1.1 --save 或者直接在 package.json 中修改,因為之后的版本修改了 api,以下的代碼是針對 0.1.1 的 api,有空我修改下)。

var cheerio = require('cheerio')
  , superagent = require('superagent-charset')
  , express = require('express');

var url = 'http://acm.hdu.edu.cn/statistic.php?pid=1000';
var app = express();

app.get('/', function (req, res, next) {

  superagent.get(url)
    .charset('gbk')
    .end(function (err, sres) {
      var html = sres.text;
      var $ = cheerio.load(html, {decodeEntities: false});
      var ans = $('.table_text td a').eq(0).html();
      res.send(ans);
    });

});

app.listen(3000, function () {
  console.log('app is listening at port 3000');
});

使用非常簡單,只需要引入 superagent-charset 模塊,且在鏈式調用時加入 charset 參數即可。superagent-charset 模塊包括了 superAgent 模塊以及 iconv-lite 模塊。源碼可以參考 Github

方法二:

直接用 iconv-lite 模塊進行轉碼。

iconv-lite 是一個進行編碼轉換的模塊(node 默認編碼 utf-8)。需要 decode 的編碼必須是 Buffer 類型。

  • http 模塊:

      http.get(url, function(sres) {
        var chunks = [];
    
        sres.on('data', function(chunk) {
          chunks.push(chunk);
        });
    
        sres.on('end', function() {
          // 將二進制數據解碼成 gb2312 編碼數據
          var html = iconv.decode(Buffer.concat(chunks), 'gb2312');
          var $ = cheerio.load(html, {decodeEntities: false});
          var ans = $('.table_text td a').eq(0).html();
          res.send(ans);
        });
      });
    
  • request 模塊:

      request({
        url: url, 
        encoding: null  // 關鍵代碼
      }, function (err, sres, body) {
        var html = iconv.decode(body, 'gb2312')
        var $ = cheerio.load(html, {decodeEntities: false});
        var ans = $('.table_text td a').eq(0).html();
        res.send(ans);
      });
    

    用 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 出來的結果必須是不正確的。

Read More:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM