幫你統計閱讀量


又是一個簡單的爬蟲

效果

源碼

我始終相信編程在有用的同時也是有趣的,github上就有很多有意思的小項目。爬蟲肯定是其中有意思的一個點。
上次我想把阮大的《ECMAScript 6 入門》爬下來,放到一個文件里,結果代碼寫好之后,發現人家已經開源到github上了,於是白忙活一場。🤢好在我還是有點小強的基因的,所以就想寫這么一個統計博客閱讀量的東西。

其實之前寫過一個瀏覽器上的,算不上什么爬蟲,只有四行代碼。畢竟是瀏覽器,有諸多限制,比如只能知道自己的,而且還要登陸。。。看哲理

統計訪問量的幾種方法:

逛別人的博客可以發現,博客園里不少人的主頁里有統計訪問量的這么一個圖片之類的東西:

像我這樣的

高級一點的:

包括cnzz站長統計,

道理都是一樣的,當有人訪問你的主頁時,由於你的主頁上引用了統計網站的資源,比如圖片,在請求的過程中,統計網站完成計數+1。但是這樣的話,當刷新或者翻頁時,訪問量也會增加。所以訪問量不等於閱讀量。

知識點

  • promise的應用
  • http模塊發起請求
  • cheerio可選
  • 正則表達式的應用

步驟

  1. 了解博客園的url結構。
    這一步比較簡單,翻翻自己的博客就能發現,在翻頁的時候,發生改變的是查詢字符串“?page=1,2,3...”;所以在發起請求的時候,通過改變查詢字符串參數來統計博客每一頁的閱讀量。

  2. 先統計一頁的總閱讀量
    就是用http模塊向對應url發起請求,得到頁面的html數據后,利用正則匹配出我們想要的數據,代碼如下:

    var http=require('http'),
        root='http://www.cnblogs.com/imgss/';
        http.get(root +'?page=1', (res) => {
        var status = res.statusCode;
        var html = '';
        if(status == "200") {
            res.on('data', (data) => {
                html += data;
            });
            res.on('end', () => {
                var $ = cheerio.load(html);
                countStr = $('.postDesc').text();
                console.log(countStr);
                console.log('-----------------------------------------------')
                var re = /閱讀\((\d+)\)/g;
                if(!countStr) {
                    return false;
                }
                while(true) {
                    var match = re.exec(countStr); //匹配閱讀量數據
                    if(match)
                        total += +match[1];//將匹配到的數據加到total里面
                    else
                        break;
                }
                console.log('page1的閱讀量是', total);
            })
        }
    })
    
    

    這里,countStr = $('.postDesc').text();部分是先用cheerio對html進行篩選,得到.postDesc元素下面的text,然后用re表達式進行進一步匹配得到閱讀量的數據

    這里直接用re表達式匹配html也是可行的。只要摘要部分沒有類似於"閱讀()"的字符就行。

3 用promise管理並發請求。

    首先,我們把上面寫的代碼封裝成一個模塊。以便后面調用:
var cheerio = require('cheerio'),
    http = require('http');

module.exports = function(root, page) {//函數需要兩個參數,一個是root,表示根路徑,另一個是page,是一個number,表示請求第幾頁。
    return new Promise(function(resolve, reject) {//返回一個promise實例。
        var total = 0;
        http.get(root + `/default.html?page=${page}`, (res) => {
            var status = res.statusCode;
            var html = '';
            if(status == "200") {
                res.on('data', (data) => {
                    html += data;
                });
                res.on('end', () => {
                    if(!/class=\"day\"/.test(html)) {
                        console.log(`頁面${page}沒有內容`);
                        resolve(0);
                        return;
                    }
                    var $ = cheerio.load(html);
                    countStr = $('.postDesc').text();
                    var re = /閱讀\((\d+)\)/g;
                    if(!countStr) {
                        resolve(0);//頁面沒有數據時,返回0
                    }
                    while(true) {
                        var match = re.exec(html); //匹配閱讀量數據
                        if(match)
                            total += +match[1];//對當前頁面的閱讀量求和
                        else
                            break;
                    }
                    console.log(`page${page}的閱讀量是`, total);
                    resolve(total);
                })
            }
        })
    })
}

接下來,就是通過一個主循環來得到所有的頁面的總閱讀量,首先引入上面的模塊:

var onepage = require('./onepage');//引入上面的模塊;
var promiseArr = [],
    host = 'http://www.cnblogs.com/';
host += process.argv[2] ? process.argv[2] : 'imgss' + '/';//可以接受來自命令行的參數,比如可以是`node index artech`
for(let i = 1; i < 10; i++) {
    promiseArr.push(onepage(host, i));//將promise實例放到一個數組里。
}
Promise.all(promiseArr).then(function(data) {//data是存放reslove()返回值的數組。
    let sum = 0;
    for(d of data) {
        sum += d;
    }
    console.log(sum);
})

Promise.all方法就像是一個管門的,promiseArr就像一個隊列,當里面的實例都變成resolve,或者更形象一點,都成功了,Promise.all就成功了,然后就執行then方法。

4-19更新

上面的方法的缺陷在於:

  1. 沒有控制並發,把i寫成20,就會同時發起20個請求

  2. 沒有自動結束的功能,就是即使后面的頁面是空的,也會繼續請求。

改進方法是用異步函數:像下面這樣:

var onepage = require('./onepage');
var promiseArr = [],
    host = 'http://www.cnblogs.com/';
host += process.argv[2] ? process.argv[2] : 'imgss' + '/';
let i=1,sum=0;
(async function getAll(){
while(true){
    let num= await onepage(host , i++);
    if(num){
    sum += num;  
    }else{
        break;
    }
}
console.log('總閱讀量:',sum);
})();

效果:

ps:很高興自己有一篇博客破千了😆

promise講解;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM