用Promise实现队列(爬一爬慕课网HTML代码)
项目初始化
创建一个package.json文件,webstorm快捷创建package.json非常简单。
使用 npm init 快速创建。
工具模块
需要下载的的模块
- superagent 页面数据下载
- cheerio 页面数据解析
这是2个npm包,我们先下载:
npm install superagent cheerio --save
需要引入的模块
- fs
- path
引入项目依赖
const cheerio = require('cheerio'); const agent = require('superagent'); const path = require('path'); const fs = require('fs');
定义地址数组
我们希望以队列的形式逐个对这些地址进行访问,获取HTML代码,以便后续处理:
const urls = [{ page:1, url:"https://www.imooc.com/course/list?c=fe&page=1" },{ page:2, url:"https://www.imooc.com/course/list?c=fe&page=2" },{ page:3, url:"https://www.imooc.com/course/list?c=fe&page=3" }];
定义数据结构
慕课网课程列表:
对此我们定义如下的数据结构:
[ { page: 1, data: [ { title:"", // 课程标题 imgurl:"", // 课程图片 level:"", // 等级 studynum:0, // 学习人数 description:"xxxx" // 课程描述 } ...... // 每一个页面有多条课程信息 ] } ...... // 一共有多个页面 ]
superagent 页面数据下载
superagent是nodejs里一个非常方便的客户端请求代码模块,superagent是一个轻量级的,渐进式的ajax API,可读性好,学习曲线低,内部依赖nodejs原生的请求API,适用于nodejs环境下。
基本使用方法:具体的请自行点击连接查看哟...
request .get('/login') .end(function(err, res){ // code });
cheerio 页面数据解析
cheerio是一个node的库,可以理解为一个Node.js版本的jquery,用来从网页中以 css selector取数据,使用方式和jquery基本相同。
需要先loading一个需要加载html文档,后面就可以jQuery一样使用操作页面了。
基本使用方法:具体的请自行点击连接查看哟...
const cheerio = require('cheerio'); const $ = cheerio.load('<ul id="fruits">...</ul>'); $('#fruits').addClass('newClass');
使用Promise实现队列
这才是本篇文章的重头戏...
- 我们需要使用数组的一个方法 reduce()
arr.reduce([callback, initialValue])
reduce() 方法接收一个函数作为累加器(accumulator),数组中的每个值(从左到右)开始缩减,最终为一个值。
callback (执行数组中每个值的函数,包含四个参数)
initialValue (作为第一次调用 callback 的第一个参数。)
- 还有一个是Promise实现异步处理
具体是使用Promise的这个方法:
Promise.resolve()
这个方法返回一个fulfilled的Promise实例,或者原始的Promise实例。
代码实现:
// 实现队列 // 本质: 对.then()方法实现累加 let curPromise = urls.reduce((promise,curl) => { return promise.then(() => { return new Promise(resolve => { // 网络获取当前地址的网页内容 requestGet(curl,() => { resolve(); }); }); }); },Promise.resolve());
将数据写入result.json文件中
代码实现:
// 写入数据 curPromise.then(()=>{ fs.writeFile('result.json', JSON.stringify(result), function (err) { if(err) throw new Error("appendFile failed..."); console.log("数据写入success..."); }); });
完整代码
// 项目依赖 const cheerio = require('cheerio'); const agent = require('superagent'); const path = require('path'); const fs = require('fs'); // 地址数据 const urls = [{ page:1, url:"https://www.imooc.com/course/list?c=fe&page=1" },{ page:2, url:"https://www.imooc.com/course/list?c=fe&page=2" },{ page:3, url:"https://www.imooc.com/course/list?c=fe&page=3" }]; // 最终的数据 let result = []; // 数据结构 /** * [ * { * page: 1, * data: [ * {title:xx,imgurl:xx...}, * ...... * ] * } * ...... * ] */ // 发起get请求 function requestGet(urlObj,callback){ agent.get(urlObj.url) .end((err,res) => { if(err) throw new Error(err); // 分析页面 let pageJson = analysis(res.text); // 拼接数据 result.push({ page:urlObj.page, data:pageJson }); console.log(`写入第${urlObj.page}页的数据...`); // 执行回调 callback(); }); } // 对网页分析 function analysis(data){ let page = []; let $ = cheerio.load(data); let courseArr = $(".course-list").find(".course-card-container"); courseArr.each((index,element) => { let _this = $(element); // 组装数据 page.push({ title:_this.find(".course-card-name").text(), imgurl:path.join("http:",_this.find(".course-card-top img").attr("src")), level:_this.find(".course-card-info span:first-child").text(), // level:_this.find(".icon-set_sns").parent().prev().text(), studynum:_this.find(".icon-set_sns").parent().text(), description:_this.find(".course-card-desc").text() }); }); return page; } // 实现队列 // 本质: 对.then()方法实现累加 let curPromise = urls.reduce((promise,curl) => { return promise.then(() => { return new Promise(resolve => { // 具体的内容 requestGet(curl,() => { resolve(); }); }); }); },Promise.resolve()); // 写入数据 curPromise.then(()=>{ fs.writeFile('result.json', JSON.stringify(result), function (err) { if(err) throw new Error("appendFile failed..."); console.log("数据写入success..."); }); });
启动项目
node app.js
可以看到终端有次序的输出了以下内容:
当打开生成的 result.json 文件,其结构也符合我们的预期:
至此,这篇文章也就结束啦,如果您有好的想法请留言哟。
持续学习中...
相关推荐
lupeng 2020-11-14
sjcheck 2020-11-10
sjcheck 2020-11-03
meylovezn 2020-08-28
owhile 2020-08-18
Francismingren 2020-08-17
pythonclass 2020-07-29
sunzhihaofuture 2020-07-19
爱读书的旅行者 2020-07-07
行吟阁 2020-07-05
tianqi 2020-07-05
行吟阁 2020-07-04
冰蝶 2020-07-04
lyg0 2020-07-04
owhile 2020-07-04
opspider 2020-06-28
lengyu0 2020-06-28
tianqi 2020-06-21
dadaooxx 2020-06-16