前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Nodejs编写爬虫处理乱码详解

Nodejs编写爬虫处理乱码详解

作者头像
挥刀北上
发布2019-08-06 16:35:12
2K0
发布2019-08-06 16:35:12
举报
文章被收录于专栏:Node.js开发Node.js开发Node.js开发
当我们用nodejs编写爬虫向目标网站爬取网页时,目标网站的编码格式可能不是utf8格式的,而在nodejs中大部分处理数据的api默认都是用utf8,所以这种情况下就会出现乱码。下面笔者将通过不同的例子来演示请求结果出现乱码的各种情况,并解决。

我们准备两个目标网站:第一个是网页编码格式为utf8的百度https://www.baidu.com/,如何查看目标网站的编码格式呢?只需要查看查看网页源代码就可以了,如图:

另外一个网站为:http://www.biqugew.com/book/15/,编码格式为gbk,如图:

首先我们用nodejs的http模块分别尝试去请求这两个网站,看看得到什么结果,首先我们用http模块请求百度,代码如下:

const http = require('http');
let options = {
    host:'www.baidu.com',
    port:80
};
let req = http.request(options,(res)=>{
    let info = '';
    res.on('data',(chunk)=>{
        info+=chunk;
    })
    res.on('end',()=>{
        console.log(info);
    })
})
req.end();

打印结果为:

可以看到结果正常打印不是乱码。

下面将url地址换成上面那个编码格式为gbk的网站,代码为:

const http = require('http');
let options = {
    host:'www.biqugew.com',
    port:80,
    path:'/book/15/'
};
let req = http.request(options,(res)=>{
    let info = '';
    res.on('data',(chunk)=>{
        info+=chunk;
    })
    res.on('end',()=>{
        console.log(info);
    })
})
req.end();

打印结果为:

出现乱码了,为什么会出现乱码呢,请求百度的页面不会出现乱码,请求这个网站就会出现乱码,what the fuck? 问题出在哪里呢?

接下来看一段代码:

var buf1= Buffer.from('哈哈哈')
var buf2= Buffer.from('嘿嘿嘿')
console.log(buf1)  //打印出来的是个buffer
console.log(buf2)  //打印出来的是个buffer
var str =  buf1+buf2;   //打印出了一个字符串
//两个buffer拼接打印出来的却是一个字符串
// 这里两个buffer拼接得到的不是一个buffer而是一个字符串,
// 为什么会这样呢,原来buffer通过“+”相连会被隐式转换为字符串,
// 并且是utf8编码格式的
console.log(str,213233123321)

运行结果如图:

可以看到用加号(+)连接buffer会对其进行隐式转换,并且默认是按照utf8的格式转化的,所以我们不能用+拼接buffer,为什么会插入这样一个知识点呢?因为我们在上面的代码中就是这么干的,并且通过data事件得到的chunk就是buffer,这个buffer的编码格式与目标网站的编码格式相同。

所以请求百度的时候,百度的编码格式为uft8,用加号连接buffer默认会转化成utf8格式额字符串,而请求另一个GBK编码的网站得到的buffer是gbk格式的,此时用加号拼接buffer,还是按照默认编码格式utf8解析就会出现乱码。

那该怎么办呢?解决方案就是我们通过data事件得到所有返回的buffer,然后根据buffer相应的编码格式将其解析,得到响应内容。那这里面就包含了两个问题,1、如何拼接buffer而不会对其进行隐式转换;2、如何将buffer按照其编码格式进行解析。

首先是第一点,拼接buffer不能用+,那要怎么拼接呢,看代码:

var buf1= Buffer.from('哈哈哈')
var buf2= Buffer.from('嘿嘿嘿')
var buf3 = [buf1,buf2]
let chunkbuffer = Buffer.concat(buf3,buf1.length+buf2.length);
console.log(chunkbuffer.toString())

执行结果:

得到的是buffer,而不是字符串。

代码解释:首先定义了两个buffer,将这两个buffer放到数组中,然后调用Buffer类的concat方法拼接buffer,这个方法接受两个参数,第一个参数为要拼接的buffer的数组,第二个参数为要拼接的buffer的总长度。第二个参数可以省略,一般会带上,这样会提高性能。

将请求gbk编码格式网站的代码修改如下:

const http = require('http');
let options = {
    host:'www.biqugew.com',
    port:80,
    path:'/book/15/'
};
let req = http.request(options,(res)=>{
    let arr = [];
    res.on('data',(chunk)=>{
        arr.push(chunk)
    })
    res.on('end',()=>{
       let chunkall = Buffer.concat(arr);
       console.log(chunkall)
    })
})
req.end();

执行结果为:

完美的得到了buffer,但是这个buffer是gbk格式的,如何将gbk格式的buffer转化为字符串呢?

这里就需要用到一个npm包iconv-lite。这个包主要提供了两个方法decode和encode。decode方法解码,将buffer按照其编码格式解码输出字符串。encode将字符串转换成指定类型的buffer。

将iconv-lite应用到代码中,代码如下:

const http = require('http');
const iconv = require('iconv-lite');
let options = {
    host:'www.biqugew.com',
    port:80,
    path:'/book/15/'
};
let req = http.request(options,(res)=>{
    let arr = [];
    res.on('data',(chunk)=>{
        arr.push(chunk)
    })
    res.on('end',()=>{
       let chunkall = Buffer.concat(arr);
       let strall=iconv.decode(chunkall,'gbk')
       console.log(strall)
    })
})
req.end();

执行结果为:

用nodejs做网页爬虫最常用的库就是request了,用这个库爬取回来的网页数据会默认按照utf8编码格式解析,所以要对这个库进行一下设置,将其options参数中的encoding设置为null,测试代码如下:

var iconv = require('iconv-lite');
var request = require('request');

request({
    method: 'GET',
    uri: 'http://www.biqugew.com',
    encoding:null

}, function (error, response, body) {
    console.log(response.body)
    let gbkstr = iconv.decode(response.body,'gb2312');
    console.log(gbkstr)
})

原理已经介绍的差不多了,nodejs中做爬虫还有很多包,这里就不一一介绍了,只要能得到相应的buffer,并且知道目标网站的编码格式,将buffer按照其编码格式转换为字符串就可以了。

有兴趣的同学可以直接复制黏贴代码测试一下,别忘了用npm安装相应的包。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-02-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 nodejs全栈开发 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档