nodejs使用superagent爬取網站內容中文亂碼的解決方法

使用superagent爬取網站內容,當網頁編碼不是utf-8編碼時,中文就會返回亂碼,原因是superagent只支持utf-8的網頁編碼,我們可以使用其擴展的一個npm模塊superagent-charset

superagent-charset使用說明

superagent-charset擴展了superagent的功能,使其可以手動指定編碼功能。

  1. 安裝
$ npm i superagent-charset
  1. 使用
    使用.charset(encoding)方法,就可以指定編碼,詳細如下:
var assert = require('assert');
var request = require('superagent-charset');
request
    .get('http://www.sohu.com/')
    .charset('gbk')
    .end(function(err,res) {
         assert(res.text.indexOf('搜狐') > -1);
  });

潛在問題

到目前為止,僅僅是解決了我們如何設置編碼的問題,但是通常我們在爬取網頁的時候,都是動態爬取的,也就是說并不是人工來指定網頁的編碼,那么如何才能做到動態指定網頁編碼呢?可以這么來做:

  1. 動態獲取網站編碼
  1. 指定網站編碼并爬去

如何動態獲取網站編碼呢?
為了瀏覽器能正常渲染網頁信息,網站通常都會在設置meta charset信息,如

<meta charset='utf-8'>

或者

<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

我們可以寫一個正則匹配規則,來匹配這段信息中的charset內容來獲取編碼,如下:

var charset = "utf-8";
var arr = res.text.match(/<meta([^>]*?)>/g);
if (arr) {
    arr.forEach(function (val) {
        var match = val.match(/charset\s*=\s*(.+)\"/);
        if (match && match[1]) {
            if (match[1].substr(0, 1) == '"')match[1] = match[1].substr(1);
            charset = match[1].trim();
        }
    })
}

當然,前提是我們需要將網頁先爬下來。完整的代碼如下:

parseUrl: function (url, callback) {
    async.waterfall([
            function (callback) {   // 動態獲取網站編碼
                superagent.get(url).end(function (err, res) {
                    var charset = "utf-8";
                    var arr = res.text.match(/<meta([^>]*?)>/g);
                    if (arr) {
                        arr.forEach(function (val) {
                            var match = val.match(/charset\s*=\s*(.+)\"/);
                            if (match && match[1]) {
                                if (match[1].substr(0, 1) == '"')match[1] = match[1].substr(1);
                                charset = match[1].trim();
                            }
                        })
                    }
                    callback(err, charset)
                })
            }, function (charset, callback) {   // 內容爬取
                superagent
                    .get(url)
                    .charset(charset)
                    .end(function (err, res) {
                        if (err) {
                            console.log(err);
                            callback(err);
                            return;
                        }
                        var model = {};
                        var $ = cheerio.load(res.text);
                        var title = _.trim($('title').text());
                        if (title.indexOf('-') > 0) {
                            var strs = _.split(title, '-');
                            model.title = _.trim(title.substr(0, title.lastIndexOf('-')));
                            model.source = _.trim(_.last(strs));
                        } else {
                            model.title = _.trim(title);
                        }
                        callback(err, model);
                    })
            }
        ],
        function (err, model) {
            callback(err, model);
        });
}

整體思路:

  1. 現將網頁內容爬下來,動態獲取編碼
  2. 再用得到的編碼再爬一次。

所以,弊端就是:同一個頁面要爬兩次!同一個頁面要爬兩次!同一個頁面要爬兩次!

謹慎使用!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,269評論 25 708
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,923評論 18 139
  • https://nodejs.org/api/documentation.html 工具模塊 Assert 測試 ...
    KeKeMars閱讀 6,396評論 0 6
  • Node基本 node的最大特性莫過于基于事件驅動的非阻塞I/O模型。 node通過事件驅動的方式處理請求,無須為...
    AkaTBS閱讀 2,205評論 0 11
  • 第二章 不是他 “你在哪個房間幾床啊?” 聽著手機里焦急的聲音,我淡淡苦笑著。一番爭吵后的N天,這個轉身摔了車...
    淳_7d93閱讀 229評論 0 2