Node 爬蟲入門

邊作邊學效率更高,爬蟲是node的適用場景之一,關於爬蟲的另外一篇文章
爲了驗證「簡書上,經驗總結、資料歸集類技術文章更容易上熱榜」的猜測,能夠作一個爬蟲:爬取簡書程序員專題熱門文章前999篇,統計每篇文章的代碼塊數量(爲何是統計代碼塊數量,對於人來講,經過一篇文章的標題內容來判斷文章的類型是一件垂手可得的事,然而對於計算機來講,這倒是一件困難的事情,這已經屬於人工智能的範疇了。然而獲取文章的代碼塊數量對於計算機來講就容易得多了,能夠認爲,代碼塊爲0或者較少的文章,屬於經驗類文章,代碼塊數量較多的文章若是不是資料歸集的話,多半就屬於談源碼實現的了)javascript

目錄

知識點

  1. http.request:node http 模塊的request方法能夠做爲http client向服務器發起http請求,爬蟲須要向目標連接發起http請求來得到頁面信息
  2. cheerio:經過 http 請求到的頁面信息,因爲缺少瀏覽器的dom解析,看起來就是一段凌亂的字符串,實在糟糕。好在咱們能夠使用 cheerio 庫將其解析爲 dom ,這樣咱們就能夠使用相似 jquery 的語法去分析頁面信息
  3. promise:因爲 node 單線程的特性,不可避免的須要用到大量異步編程的寫法,層層嵌套的回調寫法已經 low 了,來試試 promise 的寫法

實現步驟

拉取頁面列表


首先須要拿到程序員專題熱門列表的請求連接

列表連接

ajax請求,須要使用chrome dev tools,拉到底部還能加載更多:java

//order_by=likes_count 表示按照熱門進行排序
//page是分頁參數,每頁9條,咱們能夠經過改變page=0~100來拉取900篇文章
http://www.jianshu.com/collections/16/notes?order_by=likes_count&page=2複製代碼

下一步經過這個連接拉取列表數據node

/** - 建立promise */
    Seek.prototype.createPromise = function(i) {
        var options = {
            url: 'http://www.jianshu.com/collections/16/notes?order_by=likes_count&page=' + i,
            type: 'get'
        }
        return new Promise(function(resolve, reject) {
            options.callback = function(data, _setCookie) {
                resolve(data);
            }
            request(options, null);
        });
    }複製代碼

能夠建立一個promise對象來發起request請求(request的封裝就不貼出來了,實驗證實,代碼塊太多的文章不容易上熱榜~~)jquery

起初個人作法是同時建立拉取1~100頁數據的100個promise對象,同時異步的發起100個request請求,然而這樣的作法會有幾十個請求請求失敗(興許是簡書那邊作了限制),因此,仍是耐心點,每次發起5個請求,直到100頁都請求成功git

/** * 遞歸的請求,每次併發的請求5個 */
    Seek.prototype.seek = function(callback) {
        var self = this;
        times++;
        var ot = times;
        var promise = Promise.all([
            self.createPromise(times),
            self.createPromise(++times),
            self.createPromise(++times),
            self.createPromise(++times),
            self.createPromise(++times)
        ]);
        promise.then(function(result) {
            console.log("seekList totals:" + times);
            pages = pages.concat(result);
            if (times < totalPage) {
                self.seek(callback);
            } else {
                callback(pages);
            }
        });
    }複製代碼

拿到全部的列表數據以後,就能夠使用cheerio庫來分析列表頁面,抓取文章詳情連接(在這一步以前你一樣須要使用chrome dev tools工具分析頁面結構)程序員

/** * 使用cheerio載入列表頁面 */
    Analyse.prototype.load = function(data, i) {
        return new Promise(function(resolve, reject) {
            var $ = cheerio.load(data);
            var pages = [];
            var els = $('.article-list li');
            if(els.length === 0) {
                console.warn('load error page:' + i );
                resolve([]);
            }
            els.each(function(index) {
                if ($(this).attr('class') === 'have-img') {
                    pages.push($(this).children('a').attr('href'));
                } else {
                    pages.push($(this).children('div').children('.title').children('a').attr('href'));
                }

                if(index === els.length - 1) {
                    resolve(pages);
                }
            });
        });

    }複製代碼

拉取頁面詳情,分析統計


從上一步中拿到900篇熱門文章的地址以後,須要再次去抓取文章詳情頁面,一樣的每次查5篇,使用chrome dev tools分析得知,簡書文章的代碼塊使用的都是 <code></code>標籤,統計此標籤出現的數量就能夠了

/** * 建立promise */
    Seek.prototype.createPromise = function(url) {
        var options = {
            url: 'http://www.jianshu.com' + url,
            type: 'get'
        }
        return new Promise(function(resolve, reject) {
            options.callback = function(data, _setCookie) {
                var $ = cheerio.load(data);
                //頁面標題
                var title = $('h1.title').text();
                //代碼塊數量
                var codes = $('code').length;
                if(codes === 0) {//代碼塊爲0的總數
                    zeroCount++;
                } else if(codes <= 10) {//代碼塊爲<=10的總數
                    oneToTen++;
                } else if(codes <= 20) {//代碼塊<=20的總數
                    elToTwo++;
                } else {//代碼塊>20的總數
                    beyondTwo++;
                }
                resolve({
                    title: title,
                    codes: codes
                });
            }
            request(options, null);
        });
    }複製代碼

生成統計頁面


數據總須要一個展現的地方,使用nunjucks做爲頁面模板,注入抓取到的數據,在使用echarts生成統計圖表,就是這個feel, 結果頁面

統計結果

總結


開發爬蟲是一件很酷的事情,在這個過程當中還能學到知識,提高學習興趣,從爬蟲作起~~
源碼

下一篇文章講 Node 爬蟲進階,敬請關注github

補充說明:代碼大半年前些的,簡書的接口和頁面結構已經作了改版,可能抓取不到想要的結果,若是感興趣,能夠按照思路和步驟改造如今的代碼,本身動手豐衣足食ajax

相關文章
相關標籤/搜索