帮你统计阅读量

news/2024/7/19 12:29:46 标签: 爬虫

爬虫">又是一个简单的爬虫

效果

源码

我始终相信编程在有用的同时也是有趣的,github上就有很多有意思的小项目。爬虫肯定是其中有意思的一个点。
上次我想把阮大的《ECMAScript 6 入门》爬下来,放到一个文件里,结果代码写好之后,发现人家已经开源到github上了,于是白忙活一场。?好在我还是有点小强的基因的,所以就想写这么一个统计博客阅读量的东西。

其实之前写过一个浏览器上的,算不上什么爬虫,只有四行代码。毕竟是浏览器,有诸多限制,比如只能知道自己的,而且还要登陆。。。看哲理

统计访问量的几种方法:

逛别人的博客可以发现,博客园里不少人的主页里有统计访问量的这么一个图片之类的东西:

像我这样的

1016471-20170330225511305-1484703495.png

高级一点的:

1016471-20170330225943180-1877392184.png

包括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);
})();

效果:

1016471-20170419211236556-1067662246.gif

ps:很高兴自己有一篇博客破千了?

promise讲解;

转载于:https://www.cnblogs.com/imgss/p/6628956.html


http://www.niftyadmin.cn/n/915133.html

相关文章

android优化启动时间

转自&#xff1a;https://source.android.com/devices/tech/perf/boot-times 本文档提供了有关改进特定 Android 设备的启动时间的合作伙伴指南。启动时间是系统性能的重要组成部分&#xff0c;因为用户必须等待启动完成后才能使用设备。对于较常进行冷启动的汽车等设备而言&am…

iOS -- 字符串(NSString *)转uint8_t的两种方法

// 第一种 NSString *connID ((Collector *)weakSelf.globalMutableArray[i]).orignalConnID;const uint8_t a [[connID substringToIndex:2] intValue];NSRange bRange {2, 2};const uint8_t b [[connID substringWithRange:bRange] intValue];NSRange cRange {4, 2};con…

form表单验证失败,阻止表单提交

form表单验证失败&#xff0c;阻止表单提交 效果演示&#xff1a; 贴上完整代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Document</title><script type"text/javas…

android studio 导入工程

1AndroidStudio 方法/步骤 打开自己的AndroidStudio&#xff0c;如图&#xff1a; 点击“File”的按钮&#xff0c;然后选择“Import Project”&#xff0c;如图&#xff1a; 找到你要导入的程序&#xff0c;最好选择build.gradle文件&#xff0c;如图&#xff1a; 选择“Next”…

耳机jack构造及在应用时可能出现的问题

转自 https://www.cnblogs.com/Peter-Chen/p/3999212.html 目前市场上耳机分为4环耳机&#xff08;图1所示&#xff0c;iphone型&#xff09;和3环耳机&#xff08;图2所示&#xff09;。4环耳机称为headset&#xff0c;3环耳机称为headphone&#xff0c;两者之间的区别就是4环…

Html p标签文本缩进

<style type"text/css">p {text-indent: 2em;/*em是相对单位&#xff0c;2em即现在一个字大小的两倍*/} </style>

Java点滴-ListInteger list; 中尖括号的意思

这是jdk1.5后版本才有的新特性&#xff0c;泛型&#xff0c;指定传入的类型。这样定义之后&#xff0c;这个list只能接收Integer的对象。 以前没有加这个&#xff0c;传入的都是Object类型的&#xff0c;取出来的时候要强制类型转换为自己想要的类型。 现在这样就不用强制类型转…

音频处理入门笔记

转自 https://blog.csdn.net/imyfriend/article/details/9330043 ES: Echo Suppresion EES: Enhanced Echo Suppresion AEC: Acoustic Echo Cancellation 声学回声消除。在一般的VOIP软件或视频会议系统中&#xff0c;假设我们只有A和B两个人在通话&#xff0c;首先&#xf…