Node.js爬虫-爬取慕课网课程信息
第一次学习Node.js爬虫,所以这时一个简单的爬虫,Node.js的好处就是可以并发的执行
这个爬虫主要就是获取慕课网的课程信息,并把获得的信息存储到一个文件中,其中要用到cheerio库,它可以让我们方便的操作HTML,就像是用jQ一样
开始前,记得
npm install cheerio
为了能够并发的进行爬取,用到了Promise对象
//接受一个url爬取整个网页,返回一个Promise对象
function getPageAsync(url){
return new Promise((resolve,reject)=>{
console.log(`正在爬取${url}的内容`);
http.get(url,function(res){
let html = ''; res.on('data',function(data){
html += data;
}); res.on('end',function(){
resolve(html);
}); res.on('error',function(err){
reject(err);
console.log('错误信息:' + err);
})
});
})
}
在慕课网中,每个课程都有一个ID,我们事先要把想要获取课程的ID写到一个数组中,而且每个课程的地址都是一个相同的地址加上ID,所以我们只要把地址和ID拼接起来就是课程的地址
const baseUrl = 'http://www.imooc.com/learn/';
const baseNuUrl = 'http://www.imooc.com/course/AjaxCourseMembers?ids=';
//获取课程的ID
const videosId = [773,371];
为了使获取每个课程内容时并发执行,要使用Promise中的all方法
Promise
//当所有网页的内容爬取完毕
.all(courseArray)
.then((pages)=>{
//所有页面需要的内容
let courseData = []; //遍历每个网页提取出所需要的内容
pages.forEach((html)=>{
let courses = filterChapter(html);
courseData.push(courses);
}); //给每个courseMenners.number赋值
for(let i=0;i<videosId.length;i++){
for(let j=0;j<videosId.length;j++){
if(courseMembers[i].id +'' == videosId[j]){
courseData[j].number = courseMembers[i].numbers;
}
}
} //对所需要的内容进行排序
courseData.sort((a,b)=>{
return a.number > b.number;
}); //在重新将爬取内容写入文件中前,清空文件
fs.writeFileSync(outputFile,'###爬取慕课网课程信息###',(err)=>{
if(err){
console.log(err)
}
});
printfData(courseData);
});
在then方法中,pages是每个课程的HTML页面,我们还得从中提取出我们需要的信息,需要使用下面的函数
//接受一个爬取下来的网页内容,查找网页中需要的信息
function filterChapter(html){
const $ = cheerio.load(html); //所有章
const chapters = $('.chapter'); //课程的标题和学习人数
let title = $('.hd>h2').text();
let number = 0; //最后返回的数据
//每个网页需要的内容的结构
let courseData = {
'title':title,
'number':number,
'videos':[]
}; chapters.each(function(item){
let chapter = $(this);
//文章标题
let chapterTitle = Trim(chapter.find('strong').text(),'g'); //每个章节的结构
let chapterdata = {
'chapterTitle':chapterTitle,
'video':[]
}; //一个网页中的所有视频
let videos = chapter.find('.video').children('li');
videos.each(function(item){
//视频标题
let videoTitle = Trim($(this).find('a.J-media-item').text(),'g');
//视频ID
let id = $(this).find('a').attr('href').split('video/')[1];
chapterdata.video.push({
'title':videoTitle,
'id':id
})
}); courseData.videos.push(chapterdata); }); return courseData;
}
注意:在上面中将课程的学习人数设置为了0是因为学习课程人数是用Ajax动态获取,所以我在后面写了方法专门获取学习课程人数,其中用到的Trim()方法是去除文本中的空格
获取学习课程的人数:
//获取上课人数
function getNumber(url){ let datas = ''; http.get(url,(res)=>{
res.on('data',(chunk)=>{
datas += chunk;
}); res.on('end',()=>{
datas = JSON.parse(datas);
courseMembers.push({'id':datas.data[0].id,'numbers':parseInt(datas.data[0].numbers,10)});
});
});
}
这样就将想获取课程的学习人数都添加到了courseMembers数组中,在最后将学习课程的人数在赋值给相对应的课程
//给每个courseMenners.number赋值
for(let i=0;i<videosId.length;i++){
for(let j=0;j<videosId.length;j++){
if(courseMembers[i].id +'' == videosId[j]){
courseData[j].number = courseMembers[i].numbers;
}
}
}
我们获取到了数据,就要把它按照一定的格式存到一个文件中
//写入文件
function writeFile(file,string) {
fs.appendFileSync(file,string,(err)=>{
if(err){
console.log(err);
}
})
} //打印信息
function printfData(coursesData){ coursesData.forEach((courseData)=>{
// console.log(`${courseData.number}人学习过${courseData.title}\n`);
writeFile(outputFile,`\n\n${courseData.number}人学习过${courseData.title}\n\n`); courseData.videos.forEach(function(item){
let chapterTitle = item.chapterTitle;
// console.log(chapterTitle + '\n');
writeFile(outputFile,`\n ${chapterTitle}\n`); item.video.forEach(function(item){
// console.log(' 【' + item.id + '】' + item.title + '\n');
writeFile(outputFile,` 【${item.id}】 ${item.title}\n`);
})
}); }); }
最后获取到的数据:

源码:
/**
* Created by hp-pc on 2017/6/7 0007.
*/
const http = require('http');
const fs = require('fs');
const cheerio = require('cheerio');
const baseUrl = 'http://www.imooc.com/learn/';
const baseNuUrl = 'http://www.imooc.com/course/AjaxCourseMembers?ids=';
//获取课程的ID
const videosId = [773,371];
//输出的文件
const outputFile = 'test.txt';
//记录学习课程的人数
let courseMembers = []; //去除字符串中的空格
function Trim(str,is_global)
{
let result;
result = str.replace(/(^\s+)|(\s+$)/g,"");
if(is_global.toLowerCase()=="g")
{
result = result.replace(/\s/g,"");
}
return result;
} //接受一个url爬取整个网页,返回一个Promise对象
function getPageAsync(url){
return new Promise((resolve,reject)=>{
console.log(`正在爬取${url}的内容`);
http.get(url,function(res){
let html = ''; res.on('data',function(data){
html += data;
}); res.on('end',function(){
resolve(html);
}); res.on('error',function(err){
reject(err);
console.log('错误信息:' + err);
})
});
})
} //接受一个爬取下来的网页内容,查找网页中需要的信息
function filterChapter(html){
const $ = cheerio.load(html); //所有章
const chapters = $('.chapter'); //课程的标题和学习人数
let title = $('.hd>h2').text();
let number = 0; //最后返回的数据
//每个网页需要的内容的结构
let courseData = {
'title':title,
'number':number,
'videos':[]
}; chapters.each(function(item){
let chapter = $(this);
//文章标题
let chapterTitle = Trim(chapter.find('strong').text(),'g'); //每个章节的结构
let chapterdata = {
'chapterTitle':chapterTitle,
'video':[]
}; //一个网页中的所有视频
let videos = chapter.find('.video').children('li');
videos.each(function(item){
//视频标题
let videoTitle = Trim($(this).find('a.J-media-item').text(),'g');
//视频ID
let id = $(this).find('a').attr('href').split('video/')[1];
chapterdata.video.push({
'title':videoTitle,
'id':id
})
}); courseData.videos.push(chapterdata); }); return courseData;
} //获取上课人数
function getNumber(url){ let datas = ''; http.get(url,(res)=>{
res.on('data',(chunk)=>{
datas += chunk;
}); res.on('end',()=>{
datas = JSON.parse(datas);
courseMembers.push({'id':datas.data[0].id,'numbers':parseInt(datas.data[0].numbers,10)});
});
});
} //写入文件
function writeFile(file,string) {
fs.appendFileSync(file,string,(err)=>{
if(err){
console.log(err);
}
})
} //打印信息
function printfData(coursesData){ coursesData.forEach((courseData)=>{
// console.log(`${courseData.number}人学习过${courseData.title}\n`);
writeFile(outputFile,`\n\n${courseData.number}人学习过${courseData.title}\n\n`); courseData.videos.forEach(function(item){
let chapterTitle = item.chapterTitle;
// console.log(chapterTitle + '\n');
writeFile(outputFile,`\n ${chapterTitle}\n`); item.video.forEach(function(item){
// console.log(' 【' + item.id + '】' + item.title + '\n');
writeFile(outputFile,` 【${item.id}】 ${item.title}\n`);
})
}); }); } //所有页面爬取完后返回的Promise数组
let courseArray = []; //循环所有的videosId,和baseUrl进行字符串拼接,爬取网页内容
videosId.forEach((id)=>{
//将爬取网页完毕后返回的Promise对象加入数组
courseArray.push(getPageAsync(baseUrl + id));
//获取学习的人数
getNumber(baseNuUrl + id);
}); Promise
//当所有网页的内容爬取完毕
.all(courseArray)
.then((pages)=>{
//所有页面需要的内容
let courseData = []; //遍历每个网页提取出所需要的内容
pages.forEach((html)=>{
let courses = filterChapter(html);
courseData.push(courses);
}); //给每个courseMenners.number赋值
for(let i=0;i<videosId.length;i++){
for(let j=0;j<videosId.length;j++){
if(courseMembers[i].id +'' == videosId[j]){
courseData[j].number = courseMembers[i].numbers;
}
}
} //对所需要的内容进行排序
courseData.sort((a,b)=>{
return a.number > b.number;
}); //在重新将爬取内容写入文件中前,清空文件
fs.writeFileSync(outputFile,'###爬取慕课网课程信息###',(err)=>{
if(err){
console.log(err)
}
});
printfData(courseData);
});
Node.js爬虫-爬取慕课网课程信息的更多相关文章
- 养只爬虫当宠物(Node.js爬虫爬取58同城租房信息)
先上一个源代码吧. https://github.com/answershuto/Rental 欢迎指导交流. 效果图 搭建Node.js环境及启动服务 安装node以及npm,用express模块启 ...
- Node.js 爬虫爬取电影信息
Node.js 爬虫爬取电影信息 我的CSDN地址:https://blog.csdn.net/weixin_45580251/article/details/107669713 爬取的是1905电影 ...
- Python爬虫之爬取慕课网课程评分
BS是什么? BeautifulSoup是一个基于标签的文本解析工具.可以根据标签提取想要的内容,很适合处理html和xml这类语言文本.如果你希望了解更多关于BS的介绍和用法,请看Beautiful ...
- python爬虫:爬取慕课网视频
前段时间安装了一个慕课网app,发现不用注册就可以在线看其中的视频,就有了想爬取其中的视频,用来在电脑上学习.决定花两天时间用学了一段时间的python做一做.(我的新书<Python爬虫开发与 ...
- 手把手教你用Node.js爬虫爬取网站数据
个人网站 https://iiter.cn 程序员导航站 开业啦,欢迎各位观众姥爷赏脸参观,如有意见或建议希望能够不吝赐教! 开始之前请先确保自己安装了Node.js环境,还没有安装的的童鞋请自行百度 ...
- node.js爬虫爬取拉勾网职位信息
简介 用node.js写了一个简单的小爬虫,用来爬取拉勾网上的招聘信息,共爬取了北京.上海.广州.深圳.杭州.西安.成都7个城市的数据,分别以前端.PHP.java.c++.python.Androi ...
- node js 爬虫爬取静态页面,
先打一个简单的通用框子 //根据爬取网页的协议 引入对应的协议, http||https var http = require('https'); //引入cheerio 简单点讲就是node中的jq ...
- node:爬虫爬取网页图片
代码地址如下:http://www.demodashi.com/demo/13845.html 前言 周末自己在家闲着没事,刷着微信,玩着手机,发现自己的微信头像该换了,就去网上找了一下头像,看着图片 ...
- Python爬虫项目--爬取自如网房源信息
本次爬取自如网房源信息所用到的知识点: 1. requests get请求 2. lxml解析html 3. Xpath 4. MongoDB存储 正文 1.分析目标站点 1. url: http:/ ...
随机推荐
- 在github上搭建免费的博客
github好多年前,大家都开始玩啦,我这个菜鸟近几年才开始.github不仅可以管理项目,还可以搭建博客.技术人员,一般用的博客为博客园,CSDN多一些.看到朋友们都弄一个,我也开始弄起来,先找点资 ...
- 使用Entity Framework时遇到的问题
1.运行程序时提示 ,vension does not match. 差不多是这样一个提示,具体怎么样的给忘记了. #1remove 'entity framework' from reference ...
- bzoj3939 【USACO 2015 FEB GOLD 】cow hopscotch
Description 就像人类喜欢玩"跳房子"的游戏,农民约翰的奶牛已经发明了该游戏的一个变种自己玩.由于笨拙的动物体重近一吨打,牛跳房子几乎总是以灾难告终,但这是没有阻止奶牛几 ...
- CentOS_5.6下使用cmake编译MySQL_5.5.11
MySQL 最新的版本5.5.11需要cmake编译安装,估计以后的版本也会采用这种方式,网上找了一些安装方法有些地方是错的,自己整理一份 所以特地记录一下安装步骤及过程,以供参考!1 mysql 5 ...
- 关于echarts的那些事(地图标点,折线图,饼图)
前记:离上一篇博客的发布已经过去两个月了,这期间总想写点什么,却怎么都写不出来,一直拖到了现在.现在的感觉,不是像这期间一样,想好好整理一番,写一篇好博客,却写不出来.事实发现,随心就好,较好的博客, ...
- Hadoop化繁为简-从安装Linux到搭建集群环境
简介与环境准备 hadoop的核心是分布式文件系统HDFS以及批处理计算MapReduce.近年,随着大数据.云计算.物联网的兴起,也极大的吸引了我的兴趣,看了网上很多文章,感觉还是云里雾里,很多不必 ...
- Java static 关键字详解
引言 在<Java编程思想>中有这样一段话:static方法就是没有this的方法.在static方法内部不能调用非静态方法,反过来是可以的.而且可以在没有创建任何对象的前提下,仅仅通过类 ...
- java中构造方法和this,static关键字
构造方法: 构造方法是一种特殊的方法,用于创建该类的对象,对对象的数据进行初始化 格式如下: [修饰符] 类名(形参列表){ 方法体 } 特点 A:方法名和类名相同 B:没有返回值类型,连void都 ...
- Object-C iOS纯代码布局 一堆代码可以放这里!
前言: 最近写的文章都是创业类,好吧,今天好好写写技术类的文章! 不过分享的不是IOS相关的文章,毕竟这几天在速成IOS,看的是object-c,由于速成的很快,好累! 好在现在基本已经入了点门道了, ...
- XSHELL工具上传文件到Linux以及下载文件到本地(Windows)
Xshell很好用,然后有时候想在windows和linux上传或下载某个文件,其实有个很简单的方法就是rz,sz.首先你的Linux上需要安装安装lrzsz工具包,(如果没有安装请执行以下命令,安装 ...