我们需要采集校花网的哪些数据呢?最重要的当然是校花妹子们的靓照啊!如果能看到照片又能了解学妹们的名字、生日、就读学校等信息就更完美了!
那该怎么获取这些信息呢?下面以网页: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
不知不觉写了这么多,那怎么把采集的数据保存下来的方法就放在下一篇再写吧。
未经允许不得转载:前端撸码笔记 » [nodejs实战:校花网学妹图片采集+站点发布]一、采集内容 http.request