http结合cheerio小爬虫(二)

上次用了http结合cheerio做了个超级简单的爬虫程序,地址是 http结合cheerio小爬虫(一),经过我一天的学习,发现有更加优雅的方法,今天在这里阐述一下,这次爬取的是老师所有课程目录的标题和学习人数及其章节标题。

大家都知道,JavaScript里面有个神器是Promise,用来传递异步操作的消息。现在就在上节课的基础之上,现结合Promise,重新做一下

Promise库有很多,这里用的bluebird,要先安装它 npm install bluebird

代码里面需要引入

1
var Promise = require('bluebird')

当然别忘了装cheerio哦 npm install cheerio

具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/**Created by wangyongzhi on 16/8/8.*/
//加载http模块,它的职责是负责创建web服务器,处理http相关的任务等等
var http = require('http')
/*老版本的node.js引入方式是 require('bluebird'),新版本ES6 新特性可以直接引入Promise
* 这里用的是require('bluebird')
* */
var Promise = require('bluebird')
//加载抓取网页模块cheerio
var cheerio = require('cheerio')
//所要抓取的网页
var baseUrl = 'http://www.imooc.com/learn/'
var videoIds = [348,637,259,197,134,75]
//过滤网页信息得到所需的章节信息
function filterChapters(html) {
var $ = cheerio.load(html)
var chapters = $('.chapter')
//要达到的结构
// courseData={
// title:title,
// number:number,
// videos:[{
// chapterTitle:''
// videos:[
// title:''
// id:''
// ]
// }]
// }
//课程名和学习人数
var title = $('.pr .hd .l').text()
var number = parseInt($($('.static-item .meta-value strong')[3]).text().trim(),10)
var courseData = {
title: title,
number: number,
videos: []
}
chapters.each(function (item) {
var chapter = $(this)
var chapterTitle = chapter.find('strong').text()
var videos = chapter.find('.video').children('li')
var chapterData = {
chapterTitle : chapterTitle,
videos : []
}
videos.each(function (item) {
var video = $(this).find('.studyvideo')
var videoTitle = video.text()
var id = video.attr('href').split('video/')[1]
chapterData.videos.push({
title : videoTitle,
id : id
})
})
courseData.videos.push(chapterData)
})
return courseData
}
//打印所有章节的内容
function printCourseInfo(coursesData) {
coursesData.forEach(function (courseData) {
console.log(courseData.number + '人学过' + courseData.title+'\n')
})
coursesData.forEach(function (courseData) {
console.log('###' + courseData.title + '\n')
courseData.videos.forEach(function (item) {
var chapterTitle = item.chapterTitle
console.log(chapterTitle+'\n')
item.videos.forEach(function (video) {
console.log(' 【' + video.id + '】 ' + video.title )
})
})
})
}
//异步爬取网页
function getPageAsync(url) {
return new Promise(function (resolve,reject) {
console.log('正在爬取'+url)
http.get(url,function (res) {
var html = ''
res.on('data',function (data) {
html += data;
})
res.on('end',function () {
resolve(html)
})
}).on('error',function (e) {
reject(e)
console.log('Get the course information error!')
})
})
}
//存放所有课程的html的一个数组
var fetchCourseArray = []
videoIds.forEach(function (id) {
fetchCourseArray.push(getPageAsync(baseUrl + id))
})
//多页面数据处理
Promise
.all(fetchCourseArray)
.then(function (pages) {
var coursesData = []
pages.forEach(function (html) {
var courses = filterChapters(html)
coursesData.push(courses)
})
//按学习课程人数从大到小排序
coursesData.sort(function (a,b) {
return a.number < b.number
})
printCourseInfo(coursesData)
})

如果代码不能用了,可能是慕课网把里面对应的类名改了,可以去慕课网用开发者工具查询一下,改变之后就会好了。

爬取部分结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
正在爬取http://www.imooc.com/learn/348
正在爬取http://www.imooc.com/learn/637
正在爬取http://www.imooc.com/learn/259
正在爬取http://www.imooc.com/learn/197
正在爬取http://www.imooc.com/learn/134
正在爬取http://www.imooc.com/learn/75
85531人学过进击Node.js基础(一)
55701人学过node+mongodb 建站攻略(一期)
30882人学过node建站攻略(二期)——网站升级
27385人学过进击Node.js基础(二)
20127人学过带你学习Jade模板引擎
16620人学过HTML5+CSS3实现“共嗨世界杯”
###进击Node.js基础(一)
第1章 前言
【6687】 1-1 前言 (01:20)
【6688】 1-2 为什么学习Nodejs (05:43)
...