我们需要采集校花网的哪些数据呢?最重要的当然是校花妹子们的靓照啊!如果能看到照片又能了解学妹们的名字、生日、就读学校等信息就更完美了!
那该怎么获取这些信息呢?下面以网页:http://www.xiaohuar.com/news-1-1722.html为例。
先说说采集数据的流程,首先是客户端(我们)发起请求,然后服务器(对方)响应,然后将响应内容再反馈给客户端,即可实现数据的采集。
nodejs需要引用http模块,然后通过调用http.request方法来实现发起http请求功能。http.request方法接收两个参数,options是一个类似关联数组的对象,里面包含一些请求的参数,callback表示请求后的回调。options常用的参数如下:
| 名称 | 含义 |
|---|---|
| host | 请求网站的域名或IP地址 |
| port | 请求网站的端口,默认是80 |
| methods | 请求方法,默认是GET |
| path | 请求的相对于根的路径,默认是”/”。QueryString含在其中,例如/search?query=helios |
| headers | 一个关联数组对象,为请求头的内容 |
上一段完整的代码:
var http = require('http');
var opt = {
host:'www.xiaohuar.com',
port:'80',
method:'get',//这里是发送的方法
path:'/news-1-1722.html', //这里是访问的路径
headers:{
'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322)', //伪装客户端
'X-Forwarded-For':'106.75.37.169', //伪装ip
'Content-Type':'application/x-www-form-urlencoded'
}
};
http.request(opt, function(res) {
var data = '';
res.on('data',function(chunk){
data+=chunk;
}).on('end', function(){
console.log(data);
});
}).on('error', function(e) {
console.log('Got error:'+ e.message);
}).end();
将以上代码存入一个js文件,比如getDetail.js,然后node getDetail,就会看到已经获取到对应网页的源代码了,但是呢,会有乱码,如图:

我目前了解到的原因有两点:
一、编码问题:校花网用的是gb2312编码,而nodejs默认的是utf-8,前后编码不一致所以导致乱码。
二、chunk的拼接问题导致。
先看代码,转码需要引用bufferHelper和iconv模块:
var http = require('http');
var iconv = require('iconv-lite');
var BufferHelper = require('bufferhelper');
var opt = {
host:'www.xiaohuar.com',
port:'80',
method:'get',//这里是发送的方法
path:'/news-1-1722.html', //这里是访问的路径
headers:{
'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322)', //伪装客户端
'X-Forwarded-For':'106.75.37.169', //伪装ip
'Content-Type':'application/x-www-form-urlencoded'
}
};
http.request(opt, function(res) {
var bufferHelper = new BufferHelper();//运用buffer来拼接chunk
res.on('data',function(chunk){
bufferHelper.concat(chunk);
}).on('end', function(){
var val = iconv.decode(bufferHelper.toBuffer(), 'gb2312');//转码
console.log(val);
});
}).on('error', function(e) {
console.log('Got error:'+ e.message);
}).end();

正常显示了。
再看上述两个原因,解决编码问题,用iconv模块就可以,通过iconv.decode方法把获取到的数据由gb2312编码转成utf8编码,这个比较好理解,那么chunk的拼接问题是什么问题呢?这个要从前端人员不常见的buffer类说起了。
Javascript是为浏览器而设计的,能很好的处理unicode编码的字符串,但对于二进制或非unicode编码的数据就显得无能为力。Node.js继承Javascript的语言特性,同时又扩展了Javascript语言,为二进制的数据处理提供了Buffer类,让Node.js可以像其他程序语言一样,能处理各种类型的数据了。 引自:http://blog.fens.me/nodejs-buffer/
通过上述文字可以看出buffer类是用来处理二进制数据的,而http.request获取到的数据都是二进制数据然后通过buffer类存储起来了,如将上述代码中
res.on('data',function(chunk){
的chunk console.log出来就是

每个<Buffer …>都是一个对应的chunk。如果运用data+=chunk来拼接chunk,相当于进行了buffer.toString() + buffer.toString()。如果chunk不是完整的,则toString出来后的string是存在问题的(比如一个中文字被截断)。这样出来的string就无法被iconv正常转码。详情请看:https://cnodejs.org/topic/4faf65852e8fb5bc65113403
通过bufferHelper模块则很好的避免了chunk拼接可能会出现的问题,然后再通过iconv转码就万无一失了。如果暂时不理解buffer的相关知识,则可以绕过,知道“在采集数据的时候用bufferHelper拼接chunk然后再用iconv转码就可以避免乱码”这个方法就可以了,我就是这么的拿来主义~
如此,基本就实现了采集数据的功能。 获取完了信息自然还需要把获取的信息保存下来的,不过在说保存信息之前,我觉得有必要再深入介绍一下http的request方法。
一个完整的http.request方法需要拼接好options对象,如上述代码中的opt对象:
var opt = {
host:'www.xiaohuar.com',
port:'80',
method:'get',//这里是发送的方法
path:'/news-1-1722.html', //这里是访问的路径
headers:{
'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322)', //伪装客户端
'X-Forwarded-For':'106.75.37.169', //伪装ip
'Content-Type':'application/x-www-form-urlencoded'
}
};
但是这么详细的写在很大场合下是不必要的,因为只需要传入需要采集页面的url就可以了,所以直接将url传给http.request,即把上述的opt改为
var opt= 'http://www.xiaohuar.com/news-1-1722.html';
就可以了。
当然还可以更简化:http模块还提供了http.get(options,callback)方法,用来更简单的处理GET方式的请求,它是http.request的简化版本,唯一的区别在于http.get自动将请求方法设为GET请求,同时不需要手动调用req.end();
var http = require('http');
var iconv = require('iconv-lite');
var BufferHelper = require('bufferhelper');
var url= 'http://www.xiaohuar.com/news-1-1722.html';
http.get(url, function(res) {
var bufferHelper = new BufferHelper();
res.on('data',function(chunk){
bufferHelper.concat(chunk);
}).on('end', function(){
var val = iconv.decode(bufferHelper.toBuffer(), 'gb2312');
console.log(val);
});
}).on('error', function(e) {
console.log('Got error:'+ e.message);
});
一样可以达到效果。
不过还是有很多复杂的数据采集,依然得用http.request方法。比如有的网站是有防采集措施的,这时候就需要通过拼凑opt对象中的headers属性来绕过重重难关了,比如模拟ip,模拟浏览器,写入cookie等。具体的怎么获取这些数据也不难,打开chrome浏览器,按f12,找到Network选项,点击任意一个列表,右侧的Headers中就有你想要的数据,直接上图:

撇开校花网的采集,来继续扩展一些http.request方法的相关知识,因为采集校花网只需要get方法就可以了,而有些数据是需要post方法的。
上代码:
var http = require("http");
var querystring = require('querystring');
var BufferHelper = require('bufferhelper');
var post_data = querystring.stringify({
fname: '蒙奇·D·撸码客'
});
var options = {
host: 'www.runoob.com',
port: '80',
method: 'post',//这里是发送的方法
path: '/try/ajax/demo_post2.php', //这里是访问的路径
headers: {
'Accept': '*/*',
'Connection': 'keep-alive',
'Content-Length': post_data.length,
'Content-Type': 'application/x-www-form-urlencoded',
'Cookie': 'Hm_lvt_8e2a116daf0104a78d601f40a45c75b4=1483690016,1484721224,1486192505; Hm_lpvt_8e2a116daf0104a78d601f40a45c75b4=1486196996; CNZZDATA5578006=cnzz_eid%3D38224374-1486190427-%26ntime%3D1486195827',
'Host': 'www.runoob.com',
'Origin': 'http://www.runoob.com',
'Referer': 'http://www.runoob.com/try/try.php?filename=tryajax_post2',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'
}
};
var req = http.request(options, function (res) {
var bufferHelper = new BufferHelper();
res.on('data', function (chunk) {
bufferHelper.concat(chunk);
}).on('end', function () {
console.log(bufferHelper.toString());
});
});
req.write(post_data);
req.end();
以上用到的url以及post的数据来自菜鸟教程:http://www.runoob.com/try/try.php?filename=tryajax_post2
以上代码大部分跟get方法一样,不同的就是引用querystring模块,用于处理post传入的数据,然后req.write(post_data)将数据传入。
再引伸一下,如果有的站是https的,引用https模块,var https = require("https");然后调用https.request即可,使用方法同http.request,哦对了,端口设置就不是80了,而是443。
其实http.request是比较基础的数据请求模块,通过不断的折腾以及查看别人写的代码发现,用到的更多的还是Request模块。需要注意的是,Request模块和http.request完全是两回事,http.request是node.js里自带的函数,Request模块是一个比较流行的第三方npm包,集成了很多方便功能,详情就自己看吧:
https://github.com/request/request
https://my.oschina.net/chinacaptain/blog/471114
不知不觉写了这么多,那怎么把采集的数据保存下来的方法就放在下一篇再写吧。
0 条评论。