您的位置:首页 > Web前端 > Node.js

nodejs爬虫案例笔记

2016-06-13 23:17 405 查看
用nodeJs制作一个简单的网页爬虫

主要分为三个步骤,向目标请求数据,处理数据,打印数据。需要用到的模块有http,cheerio。

1.准备步骤,引入要使用的模块

2.向目标请求数据

http.get(url,function(res){
var html='';

res.on("data",function(data){
html+=data;
})

res.on("end",function(){
var couseData=filterChapter(html);//处理

printcouse(couseData);//打印
})
}).on("error",function(){
console.log("something is error")
})


知识点:res服务器响应有两个事件,data事件是数据传输时触发,如果数据量比较大的话,会将数据分为小段小段的接受,每次都会触发data事件。end事件,所有数据接受完毕时触发。

3.处理数据

function filterChapter(html){
var $=cheerio.load(html);

var chapters=$(".chapter");

var couseData=[];

chapters.each(function(){
var chapter=$(this);
var chapterTil=chapter.find("strong").text();
var chapterCon=chapter.find(".video").children("li");

var chapterData={
chapterTil:chapterTil,
chapterCon:[]
}
chapterCon.each(function(){
var chapterDetail=$(this).find(".studyvideo");
var chapterDetailTil=chapterDetail.text();
var id=chapterDetail.attr("href").split("video/")[1];

chapterData.chapterCon.push({
title:chapterDetailTil,
id:id
})
})

couseData.push(chapterData)
})

return couseData;

}


知识点:cheerio模块几乎能够解析任何的 HTML 和 XML document,并用jquery来进行dom操作。它为服务器特别定制的,快速、灵活、实施的jQuery核心实现。

在这里是要找到课程章节名称及子栏目

4.打印数据

function printcouse(couseData){
couseData.forEach(function(item){
chapterTil=item.chapterTil;

console.log(chapterTil+"\n");

item.chapterCon.forEach(function(chapterDetail){
console.log(chapterDetail.id+chapterDetail.title+"\n")
})
})
}


以上只能抓取一个页面的课程数据,接下来是要在此基础上抓取多个页面的数据。

增加模块promise

1.对请求数据部分的处理,改成返回一个promise对象,方便后续的并发控制

function getPageAsync(url){
return new Promise(function(resolve,reject){
console.log("正在爬取课程")

http.get(url,function(res){
var html='';

res.on("data",function(data){
html+=data;
})

res.on("end",function(){
resolve(html)//resolve就是promise对象接下来要回调的函数
})
}).on("error",function(e){
reject(e)
console.log("something is error")
})
})
}


2.根据不同的url返回promise对象,将他们都放到数组里面

var videoIds=[348,259,197,75];
var fetchCouseArr=[];//promiser对象数组
videoIds.forEach(function(id){
fetchCouseArr.push(getPageAsync(baseUrl+id))//存入数组
})


3.并发控制,同时抓取多个页面数组

Promise
.all(fetchCouseArr)//all方法接受一个数组,返回多个promise对象,每个promise对象都执行接下来的操作
.then(function(pages){//pages就是每个要去爬的页面
var cousesData=[]

pages.forEach(function(pages){
var courses=filterChapter(pages)//数据处理

cousesData.push(courses)
})

cousesData.sort(function(a,b){
return a.number<b.number
})

printcouse(cousesData)//数据打印
})


知识点:promise的all方法接受一个数组参数,对于数组内的每个promise对象都执行接下来的操作,上面请求数据时最后返回的reslove(html)在这里就是then方法内的回调函数,pages参数就是请求到的html数据。

4.数据处理和数据打印原理还是和最开始一样

function filterChapter(html){
var $=cheerio.load(html);

var Title=$("#main .path>a").eq(3).children("span").text();

var number=parseInt($(".meta-value").eq(2).children("strong").text(),10);

var couseData={
Title:Title,
videos:[],
number:number
};

var chapters=$(".chapter");

chapters.each(function(){
var chapter=$(this);
var chapterTil=chapter.find("strong").text();
var chapterCon=chapter.find(".video").children("li");

var chapterData={
chapterTil:chapterTil,
chapterCon:[]
}
chapterCon.each(function(){
var chapterDetail=$(this).find(".studyvideo");
var chapterDetailTil=chapterDetail.text();
var id=chapterDetail.attr("href").split("video/")[1];

chapterData.chapterCon.push({
title:chapterDetailTil,
id:id
})
})

couseData.videos.push(chapterData)
})

return couseData;

}

function printcouse(cousesData){
cousesData.forEach(function(courseData){
console.log(courseData.number+'人学过'+courseData.Title+'\n')
})

cousesData.forEach(function(courseData){
console.log('###'+courseData.Title+'\n')

courseData.videos.forEach(function(item)
{
//console.log('###'+item.chapterTil+'\n')
var chapterTil=item.chapterTil;

console.log(chapterTil+"\n");

item.chapterCon.forEach(function(chapterDetail){
console.log(chapterDetail.id+chapterDetail.title+"\n")
})
})
})
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: