本文和大家分享node experss做的第二个爬虫。我们来爬一下电影天堂的最新电影下载链接,有需要的朋友可以参考一下。
上周,我写了一篇关于node experss爬虫的简介。今天我们继续学习,写一个爬虫2.0版。
这次我们不爬博客园了。不如玩点新的,爬电影天堂?因为每个周末都会从电影天堂下载一部电影。
空谈不值钱,给我看看代码!
抓取页面分析
我们的目标:
1.抓取电影天堂首页,左侧获得169个最新电影链接。
2.抓取169部新电影的迅雷下载链接,同步和异步抓取。
具体分析如下:
1.我们不需要从迅雷上什么都抢,只需要下载最新上映的电影,比如下面的左栏。总共有170部电影。除去第一部(因为第一部有200部电影),总共有169部电影。
2.除了抢首页,我们点进去之后还要抢每部电影的迅雷下载链接。
环境搭建
1.需要的:node environment,express,cherrio在上一篇文章中都有介绍,这里就不介绍了:点击查看。
2.要安装的新东西:
超级代理:
功能:类似于request,我们可以用它来获取get/post等请求,并设置相关的请求头信息。与使用内置模块相比,要简单得多。
用法:
var superagent=require(' superagent ');
超级代理。get('/some-url ')。end(function(err,res){
//做点什么
});
superagent-字符集:
功能:解决编码问题,因为电影天堂的编码是gb2312,爬下来的汉字会乱码。
用法:
var superagent=require(' superagent ');
var charset=require(' superagent-charset ');
charset(超级代理);
超级代理。get('/some-url ')。charset('gb2312') //在此设置编码。end(function(err,res){
//做点什么
});
异步:
角色:Async是一个过程控制工具包,它提供了直接而强大的异步功能。这里称之为处理并发。
用法:这里需要用到的是:async.maplimit (arr,limit,iterator,callback)
MapLimit可以同时发起多个异步操作,然后一起等待回调的返回,返回一个再发起下一个。
Arr是一个数组,限制并发性。arr中的每一项都被带到迭代器中执行,执行结果传递给最后一个回调。
事件代理:
功能:eventproxy作为一个计数器,帮助你管理异步操作是否完成。完成后,它会自动调用您提供的处理函数,并将捕获的数据作为参数传递。
比如我先抓取电影天堂首页侧边栏的链接,然后就可以抓取链接里的内容了。具体功能可以点击这里。
用法:
var EP=new event proxy();
EP . after(' get _ file ',files.length,function (list) {
//将在所有文件异步执行结束后执行。
//列表数组中存在所有文件的内容
});
for(var I=0;I文件.长度;i ) {
fs.readFile(文件[i],' utf-8 ',函数(err,content) {
//触发结果事件
ep.emit('got_file ',内容);
});
}
//注意两个名字got_file必须对应。
开始爬虫
主程序在app.js这里,所以看的话可以主要看app.js。
1.首先,定义一些全局变量,导入引入的库。
var cheerio=require(' cheerio ');//可以像jquer一样操作界面
var charset=require(' superagent-charset ');//解决乱码问题:
var superagent=require(' superagent ');//发起请求
charset(超级代理);
var async=require(' async ');//异步抓取
var express=require(' express ');
var event proxy=require(' event proxy ');//过程控制
var EP=event proxy();
var app=express();
var base URL=' http://www . dytt 8 . net ';//迅雷首页链接
var newMovieLinkArr=[];//存储新电影的url
var errLength=[];//统计出错链接的数量
Var highScoreMovieArr=[] //高评分电影
2.开始爬首页迅雷首页:
//先抢迅雷首页
(功能(第页){
超级代理。获取(第页)。字符集(“gb2312”)。end(function (err,sres) {
//常规错误处理
如果(错误){
Console.log(“获取消息“页面”时出错”)
返回下一个(err);
}
var $=cheerio . load(sres . text);
//170个电影链接,注意重复。
getAllMovieLink($);
high score movie($);
/*
*过程控制声明
*当首页左侧的链接被爬取后,我们将开始爬取里面的详情页。
*/
ep.emit('get_topic_html ',' get '页面'成功');
});
})(base URL);
这里我们先抓取首页的东西,将首页抓取的页面内容传递给getAllMovieLink和highScoreMovie进行处理。
除了第一部电影,GetAllMovieLink在左栏得到了169部电影。
HighScoreMovie是左栏的第一个链接,包含了高评分的电影。
在上面的代码中,我们已经得到了一个计数器,当它结束时,我们就可以执行名称' get _ topic _ html '对应的进程,从而保证爬完第一个页面后,爬完第二个页面。
ep.emit('get_topic_html ',' get '页面'成功');
highScoreMovie的方法如下。其实我们这里没多大作用。只是我统计了一下高分电影首页的信息,懒得继续抢了。
//200多部8分以上的电影!这里只是统计数据,就不抓取了。
函数highScoreMovie($){
var url='http://www.dytt8.net' $('。co _ content 2 ul a’)。等式(0)。attr(' href ');
console . log(URL);
超级代理。获取(url)。字符集(“gb2312”)。end(function (err,sres) {
//常规错误处理
如果(错误){
Console.log('获取信息“url”时出错)
}
var $=cheerio . load(sres . text);
var elemP=$(' # Zoom p ');
var elemA=$(' # Zoom a ');
for(var k=1;k长度;k ) {
var Hurl=elemP.eq(k)。查找(' a ')。text();
if(highscoremoviearr . index of(Hurl)=-1){
highscoremoviearr . push(Hurl);
};
}
});
}
3.将左栏中的信息分开,
如下图,在首页,详细页面的链接都在这里$('。co _ content 2 ul a’)。
因此,我们遍历左列中的所有细节页面链接,并将它们保存在一个名为newMovieLinkArr的数组中。
GetAllMovieLink方法如下:
//获取首页左栏的所有链接
函数getAllMovieLink($){
var linkElem=$('。co _ content 2 ul a’);
for(var I=1;i170i ){
var URL=' http://www . dytt 8 . net ' link elem . eq(I)。attr(' href ');
//注意去重
if(newmovielinkarr . index of(URL)==-1){
newMovieLinkArr.push(网址);
};
}
}
4.抓取获得的电影详情页,提取有用的信息,比如电影的下载链接,这是我们关注的。
//命令ep重复监听emit事件(get_topic_html),在抓取get_topic_html时执行。
ep.after('get_topic_html ',1,function (eps) {
var concurrency count=0;
var num=-4;//因为是5并发,所以需要减去4。
//使用回调函数返回结果,然后取出结果中的整个结果数组。
var fetchUrl=function (myurl,callback) {
var fetchStart=新日期()。getTime();
concurrencyCount
数量=1
Console.log('现在并发数是',concurrencyCount,',被爬取的是',myurl);
超级代理。获取(我的网址)。charset('gb2312') //解决编码问题。end(function (err,ssres) {
如果(错误){
回调(err,myurl '发生错误!');
errlength . push(myurl);
返回下一个(err);
}
var time=新日期()。getTime()-fetch start;
Console.log('爬网' myurl '成功',',耗时'毫秒');
concurrency count-;
var $=cheerio . load(ssres . text);
//处理得到的结果。
getDownloadLink($,function(obj){
RES . write(' br/');
Res.write(num ',电影名-' obj . movie name);
RES . write(' br/');
Res.write ('thunderbolt下载链接-' obj . downlink);
RES . write(' br/');
RES . write(' details link-a href=' myurl ' target=' _ blank ' ' myurl ' a/');
RES . write(' br/');
RES . write(' br/');
});
var结果={
movieLink: myurl
};
回调(空,结果);
});
};
//控制最大并发为5,在结果中取出回调返回的整个结果数组。
//mapLimit(arr,Limit,iterator,[回调])
async.mapLimit(newMovieLinkArr,5,function (myurl,callback) {
fetchUrl(myurl,回调);
},函数(err,result) {
//爬虫结束后回调,可以做一些统计结果
Console.log('数据包捕获后,共捕获了-' newmovieinkarr . length '条数据');
console . log(' error-' errlength . length '数据段');
Console.log('高评分电影:==" ' highscoremoviearr . length);
返回false
});
});
一开始async.mapLimit对所有详情页做了一个并发,并发数为5,然后爬取详情页。爬取详情页的过程其实和爬取首页是一样的,这里就不做过多介绍了,然后把有用的信息打印在页面上。
5.执行该命令后的图形如下:
浏览器界面:
这样,我们爬虫的一个稍微升级的版本就完成了。可能文章不是很清楚。我已经把代码上传到github了,可以再运行一次,这样更容易理解。如果以后有时间,可能会得到爬虫的升级版本,比如将抓取的信息存储在mongodb中,然后显示在另一个页面上。而爬虫程序会添加一个定时器来定时捕捉。
注意:如果浏览器中运行的汉字出现乱码,可以将Google的编码设置为utf-8来解决;
地址:https://github.com/xianyulaodi/mySpider2
请指出任何错误。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。