[nodejs实战:校花网学妹图片采集+站点发布]一、采集内容 http.request

我们需要采集校花网的哪些数据呢?最重要的当然是校花妹子们的靓照啊!如果能看到照片又能了解学妹们的名字、生日、就读学校等信息就更完美了!

那该怎么获取这些信息呢?下面以网页: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,就会看到已经获取到对应网页的源代码了,但是呢,会有乱码,如图:

luanma.jpg

我目前了解到的原因有两点:

一、编码问题:校花网用的是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();

buluanma.jpg

正常显示了。

再看上述两个原因,解决编码问题,用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.jpg

每个<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中就有你想要的数据,直接上图:

f12.jpg

撇开校花网的采集,来继续扩展一些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

上一篇:

下一篇: