nodejs + cheerio + Promise(bluebird庫實(shí)現(xiàn))抓取慕課網(wǎng)nodejs課程數(shù)據(jù)

文章概要

使用nodejs + cheerio + Promise(bluebird庫實(shí)現(xiàn))的nodejs課程數(shù)據(jù)進(jìn)行爬取。統(tǒng)計(jì)scott老師的所有課程的情況:每個(gè)課程的課程名装盯、課程介紹秽誊、鏈接地址、課程難度等級莹规。

關(guān)于cheerio的使用

  • 請參考我的另外一篇文章 《cheerio 使用初步》

也可以參考我的另外一篇爬蟲實(shí)踐文章

準(zhǔn)備

  • 對應(yīng)的DOM結(jié)構(gòu)如下
  • 我希望的到的是如下

      課程名稱: Node.js 異步優(yōu)化
      課程介紹:本課程作為 Node.js 進(jìn)階提升系列的第一課,主要講解 Node.js 的異步代碼編程習(xí)慣以及異步代碼編程會帶來的潛在問題。通過本課程的學(xué)習(xí)窑滞,學(xué)員將學(xué)會如何將 Node.js 的異步代碼進(jìn)行改良優(yōu)化。
      課程鏈接:4510人學(xué)習(xí)
      學(xué)習(xí)人數(shù):http://www.jikexueyuan.com/course/2052.html
    

代碼 crawler.js

var http = require('http');
var cheerio = require('cheerio');
var Promise = require('bluebird');
// baseUrl + videoIds 是一個(gè)課程的
var baseUrl = 'http://www.imooc.com/learn/';
var videoIds = [348, 259, 197, 134, 75];


function filterHtml(html){
    var $ = cheerio.load(html);// 使用 cheerio模塊裝載課程頁面,使用類似jquery方式處理

   
    var course_infos = $('.course-infos');//課程信息
    var title = course_infos.find('.hd').find('.l').text().trim();//課程標(biāo)題
    var number = $($('.static-item.l')[1]).find('span').last().text().trim();//課程難度等級
    var chapters = $('.chapter');//章節(jié)(每個(gè)章節(jié)包含若干小節(jié))

    //期望返回的數(shù)據(jù)結(jié)構(gòu)哀卫,將每個(gè)html頁面處理成這個(gè)字面量對象
    /*var courseData = {
        title: title,//課程名稱
        number: number,//課程學(xué)習(xí)人數(shù)
        //課程的每個(gè)章節(jié):章節(jié)名稱巨坊,小章節(jié)數(shù)組。小章節(jié):小章節(jié)名稱此改,小章節(jié)鏈接
        videos:[{
            chapterTitle: '',
            videos: [
                title:'',
                id:''
            ]
        }]
    }*/

    var courseData = {
        videos: [],
        number: number,
        title: title
    }
    //遍歷每個(gè)章節(jié)
    chapters.each(function(item) {
        var chapter = $(this);

        var chapterTitle = chapter.find('strong').text().trim();//每個(gè)章節(jié)的標(biāo)題
        var videos = chapter.find('.video').children('li');//每個(gè)小章節(jié)DOM(數(shù)組)
        var chapterData = {
            chapterTitle : chapterTitle,
            videos: []
        }

        videos.each(function(item) {
            var video = $(this).find('.J-media-item');//每個(gè)小節(jié)的a標(biāo)簽
            var videoTitle = video.text().trim();
            var id = video.attr('href').split('video/')[1].trim();

            chapterData.videos.push({
                title: videoTitle,
                id:id
            })
        })

        courseData.videos.push(chapterData)
    })

    return courseData;
}


function printInfo(info) {
    info.forEach(function(item){
        console.log(item.number + ' 人學(xué)過 ' + item.title + '\r\n');
    });

    info.forEach(function(courseData) {
        console.log('###' + courseData.title + '\n')

        courseData.videos.forEach(function(item) {
            var chapterTitle = item.chapterTitle;

            console.log(chapterTitle + '\r\n');
            item.videos.forEach(function(video) {
                var subtext = '【' + video.id +'】' + video.title
                console.log(subtext)
            })
        })

    })
}


var fetchCourseArray = [];

videoIds.forEach(function(id) {
    fetchCourseArray.push(getPageAsync(baseUrl + id));
})


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);
            })

        }).on('error', function(e) {
            reject(e)
            console.log('出錯(cuò)了')
        })
    })
}

Promise
.all(fetchCourseArray)
.then(function(pages) {
  
    var coursesData = [];//很多課程的數(shù)組(之前是一個(gè)課程里許多個(gè)章節(jié)的數(shù)組)
    pages.forEach(function(html){
        var courses = filterHtml(html);

        coursesData.push(courses);
    })

    coursesData.sort(function(a, b){
        return a.number < b.number;//從大到小
    })

    printInfo(coursesData)
})

拉出啦溜溜

執(zhí)行

npm install --save cheerio bluebird
node crawler.js

問題

我最開始想爬取慕課網(wǎng)某個(gè)課程的學(xué)習(xí)人數(shù)

DOM結(jié)構(gòu)如下

“上次學(xué)到”趾撵、“學(xué)習(xí)人數(shù)”等四塊內(nèi)容,分別存儲在四個(gè)className為static-item的DIV中共啃。但是通過數(shù)據(jù)抓取占调,我發(fā)現(xiàn),抓出的數(shù)據(jù)“上次學(xué)到”等標(biāo)題是亂碼勋磕,然后具體的內(nèi)容如“1-1課程簡介”等是空

var number = $('.statics ').find('.static-item').html();

也許是我的這次行為被慕課網(wǎng)發(fā)現(xiàn)了妈候,觸發(fā)了自動“反扒”機(jī)制,這個(gè)機(jī)制和怎么規(guī)避挂滓,目前苦银,我還不了解,后面的文章赶站,我會繼續(xù)填坑~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末幔虏,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子贝椿,更是在濱河造成了極大的恐慌想括,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件烙博,死亡現(xiàn)場離奇詭異瑟蜈,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)渣窜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進(jìn)店門铺根,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人乔宿,你說我怎么就攤上這事位迂。” “怎么了详瑞?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵掂林,是天一觀的道長。 經(jīng)常有香客問我坝橡,道長泻帮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任计寇,我火速辦了婚禮刑顺,結(jié)果婚禮上氯窍,老公的妹妹穿的比我還像新娘。我一直安慰自己蹲堂,他們只是感情好狼讨,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著柒竞,像睡著了一般政供。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上朽基,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天布隔,我揣著相機(jī)與錄音,去河邊找鬼稼虎。 笑死衅檀,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的霎俩。 我是一名探鬼主播哀军,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼打却!你這毒婦竟也來了杉适?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤柳击,失蹤者是張志新(化名)和其女友劉穎猿推,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捌肴,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蹬叭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了状知。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片具垫。...
    茶點(diǎn)故事閱讀 39,953評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖试幽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情卦碾,我是刑警寧澤铺坞,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站洲胖,受9級特大地震影響济榨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜绿映,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一擒滑、第九天 我趴在偏房一處隱蔽的房頂上張望腐晾。 院中可真熱鬧,春花似錦丐一、人聲如沸藻糖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽巨柒。三九已至,卻和暖如春柠衍,著一層夾襖步出監(jiān)牢的瞬間洋满,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工珍坊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留牺勾,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓阵漏,卻偏偏與公主長得像驻民,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子袱饭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容