運行報錯:Cannot find module 'Promise'
var http = require('http');
var Promise = require('Promise');
//如果是版本比較老的,沒有自帶Promise,則需引入上節所說的bluebird
//var Promise = require('bluebird');
var cheerio = require('cheerio');
var baseUrl = 'http://www.xianlaiwan.cn/learn/';
var url = 'http://www.xianlaiwan.cn/learn/348';
var videoIds = [348, 259, 197, 134, 75];
function filterChapters(html){
//使用模塊cheerio在服務器解析html代碼
var $ = cheerio.load(html);? //把前面的內容裝載進來
var chapters = $('.chapter');? //通過類名,拿到每一大章
var title = $('.course-infos .path a span').text();
var number = $('.js-learn-num').text();
/*
* 期望得到的一個數據的結構:
* courseData = {
* title: title, //每一章節的標題
*? number: number, //每個課程學習的人數
*? videos:[{? //video是里面的小節,有很多視頻
* ? chapterTitle:'',? ?//每一小節的名字
* ? videos: [
*? ? ? title: '',
*? ? ? id: ''
*? ? ]
*? }]
* }
*/
var courseData = {
title: title,
number: number,
videos: []
};
chapters.each(function(item){
var chapter = $(this);? //拿到單獨的某一章
//要根據頁面的代碼的標簽去拿
var chapterTitle = chapter.find("h3").text();
var videos = chapter.find('.video').children('li')
var chapterData = {? ?//這一章的內容是一個對象自變量
chapterTitle: chapterTitle,
videos:[]
}
videos.each(function(item){
var video_a = $(this).find('.J-media-item');
var videoTitle = video_a.text();
var id = video_a.attr('href').split('video/')[1];
chapterData.videos.push({
title: videoTitle,
id: id
})
})
courseData.videos.push(chapterData);
})
return courseData;
}
function printCourseInfo(coursesData){
coursesData.forEach(function(courseDate){
console.log(courseDate.number + '人學過' + courseDate.title + '\n')
})
coursesData.forEach(function(courseData){
console.log('###' + coursesData.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 + '\n');
})
})
})
}
/*
//運行得到頁面的html源碼
http.get(url, function(res){
var html = ''
res.on('data', function(data){? //有data事件觸發的時候
html += data;
})
res.on("end", function(){
var courseData = filterChapters(html);? //把html作為一個參數傳遞給一個函數,這個函數去做信息的過濾
printCourseInfo(courseData);? //打印信息出來
})
}).on("error", function(){? ?//http注冊error事件
console.log("獲取課程數據出錯");
})
*/
//將上面的http.get()進行promise化
function getPageAsync(url){
return new Promise(function(resolve, reject){
console.log('正在爬取 ' + url);
http.get(url, function(res){
var html = ''
res.on('data', function(data){? //有data事件觸發的時候
html += data;
})
res.on("end", function(){
resolve(html); //將html傳遞下去
//var courseData = filterChapters(html);? //把html作為一個參數傳遞給一個函數,這個函數去做信息的過濾
//printCourseInfo(courseData);? //打印信息出來
})
}).on("error", function(e){? ?//http注冊error事件
reject(e); //爬蟲出錯
console.log("獲取課程數據出錯");
})
})
}
var fetchCourseArray = [];
videoIds.forEach(function(id){
fetchCourseArray.push(getPageAsync(baseUrl + id));? //組裝之后是一個Promise對象的數組
})
//爬取多個課程里面的章節信息
Promise
.all(fetchCourseArray) //數組里就是一個一個的promise
.then(function(pages){? //通過then方法拿到傳遞下來的結果,多個頁面的數據
//進行信息的加工
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);
})
2018-09-04
不用require("Promise")。直接使用就可以了