接口应用小玩具-博客园积分排名变动监控工具

小玩具-博客园积分排名变动监控工具

一个简单的在线服务监控和提醒工具

1   概述

前段时间自己准备重新开启自己的博客园,然后还和一些圈子里面的朋友夸下海口,自己要开始像打游戏那样,进行博客园的 天梯 攀升。持续的发一些优质的文章或者随笔,然后不断地提升自己博客园的积分和排名,看自己最终将稳定在多少。

这样就造成了自己有了一个 强迫症 :

经常有事没事就去刷自己的博客,看排名变化了没(确实有点小神经质了)。然后自己也有一些关注的人,也关心着他们的排名,所以也在看自己的同时也刷着别人的页面,确实挺无聊的。

这样浪费了自己不少时间和精力,所以决定写个脚本来帮自己来做这个事情吧。

主要实现如下功能:

  • 根据指定的博客ID获取其积分和排名
  • 监测积分和排名数值的变化
  • 如果有变化会发邮件通知
  • 程序能够一直运行

2   引申场景

本文为了让文章 接地气 ,所以就使用了如上的场景。

其实本文本质上所阐述的内容本质上是一个简单的 在线服务监控和提醒工具 ,可以广泛的应用于对那些需要 7×24h 持续稳定运行的服务进行监控。只要是状态值发生了变化,就立刻进行邮件或者短信通知。在智能手机如此普遍的今天,这些消息都可以及时的推送到手机上面,能够让开发人员尽快发现服务故障并进行排查,减少IT生产损失。

3   原理分析

在博客园里面,每个用户都会有一个ID,比如我的博客的ID是 beer,然后用户的主页的格式一般www域名后面带上ID路径,比如我的主页就是:

http://www.cnblogs.com/beer/

博客园为每个用户提供了积分和排名的插件,而且一般情况下,用户都会在自己的博客主页上面加上此插件。毕竟,很多人在辛苦整理了学习笔记之后,也会关注一下自己的影响力的。如果用户在自己的博客首页加上了此插件,那么就可以在个人博客首页看到如前面所示的 积分和排名 了。

本文研究的对象就是:加入了 积分和排名 的个人博客园首页。毕竟还没有找到博客园官方提供的获取此数据的API接口。

一般查看http页面的接口,就通过web调试利器 chrome :

可以看出,在浏览器里面输入博客域名地址之后,浏览器最终呈现的内容并不是一次性的载入的。然后对主要的通讯接口进行内容查看:

发现和 积分与排名 数据相关的接口为:

http://www.cnblogs.com/beer/mvc/blog/sidecolumn.aspx?blogApp=beer

所有的侧边栏内容是通过一个独立的api来实现的。显然这个api的格式也是有一定的模板的,也是一个和博客的ID相关的URL,有两个地方是由ID动态生成的(中间一个,最后一个)。这个特性有用于我们最后将工具做成一个通用的工具,只要输入相应的博客园ID,就可以知道其api了,从而获取其积分和排名了。

4   实现方式

通过以上的分析,可以知道,要达到如上所提到的 目的 ,主要的技术手段如下:

  1. 找到用户的博客ID
  2. 通过http请求获取 积分和排名 页面的内容
  3. 解析页面获取 积分和排名 的数值
  4. 比较本次数值和上次数值的区别,如果有区别则发起通知
  5. 做一个以 博客ID 为参数的定时请求的线程
  6. 做一个无限循环的主线程,可以启用不同的 博客ID 的线程

主要功能实现如下:

主要用的标准库:

  • 解析HTML

    BeautifulSoup

  • 发起HTTP请求

    requests

  • 运行日志记录

    logging

自己写的一些包装的库:

  • MailMsg

    发送邮件的对象(封装的smtplib邮件库)

  • dtlog

    对logging进行的封装的指定格式的日志输出(纯粹是方便调试)

由于这两个方法具有很强的独立性,此处就不再写具体实现,用户可以自己用 print 替代 dtlog 的功能,使用 smtplib 实现MailMsg即可以运行如下程序。

# coding=utf-8
"""获取博客的排名并自动邮件通知
"""
from bs4 import BeautifulSoup
from time import sleep
import requests
import logging
import thread

from dtlib.notice import MailMsg
from dtlib.dtlog import dlog

__author__ = 'Harmo'


def get_nums(blogs_des):
    """
    get page ranks from string
    :param blogs_des:
    :return:
    """
    split_str = blogs_des.split('-')[1].strip()
    return split_str


class BlogRankMonitor(object):
    """
    博客园积分排名监控工具
    """
    def __init__(self, id):
        self.gap_seconds = 60 * 30  # 间隔时间为30min
        self.url_fmt = 'http://www.cnblogs.com/%s/mvc/blog/sidecolumn.aspx?blogApp=%s'
        self.id = id
        self.score = 0
        self.rank = 0
        self.his_score = 0
        self.his_rank = 0

    def get_blog_ranks(self):
        """
        解析页面获取博客积分和排名
        :return:
        """
        url = self.url_fmt % (self.id, self.id)
        res = requests.get(url)
        soup = BeautifulSoup(res.text)
        lis = soup.findAll('div')

        for item in lis:
            if 'sidebar_scorerank' == item.get('id'):
                li_lists = item.findAll('li')

                for li_item in li_lists:
                    if u'积分' in li_item.text:
                        self.score = get_nums(li_item.text)
                    elif u'排名' in li_item.text:
                        self.rank = get_nums(li_item.text)
                    else:
                        print 'Error'
            continue

    def monitor_score_rank(self):
        """
        监控博客积分及排名的变化
        :return:
        """
        while True:
            self.get_blog_ranks()
            if self.score != self.his_score or self.rank != self.his_rank:
                # region 发送邮件
                mail_title = '[e-notice]:blog-rank-changes'
                mail_body = "[%s]time-(score,rank):old-(%s,%s),now-(%s,%s)" \
                            % (
                                self.id,
                                self.his_score, self.his_rank,
                                self.score, self.rank
                            )
                mail_obj = MailMsg()
                mail_obj.set_title(mail_title)
                mail_obj.set_body(mail_body)
                mail_obj.send()
                dlog.debug('send mail message:%s' % self.id)
                # endregion
                self.his_score = self.score
                self.his_rank = self.rank

            sleep(self.gap_seconds)

    def start_score_rank_thread(self):
        """
        开启监控的线程
        :return:
        """
        thread.start_new_thread(self.monitor_score_rank, ())


if __name__ == '__main__':
    logging.getLogger("urllib3.connectionpool").setLevel(logging.WARNING)

    id_list = [
        'zhangfei',
        'beer'
    ]

    for id in id_list:
        blog = BlogRankMonitor(id)
        blog.start_score_rank_thread()

    #让主线程一直运行
    while 1:
        sleep(3600)

 

5   发布与部署

此脚本文件名称为 blogs_rank_demo.py ,在服务器上执行如下命令:

nohup python blogs_rank_demo.py &

即可在后台一直运行,如果怕机器重启后此进程结束掉,则可以在 /etc/rc.local 里面设置启动项。

当然,如果熟悉一些进程管理工具的同学,则可以使用更高级的工具,例如 supervisor 进行进程管理,这样会使得此服务的运行更稳定,更可控一些,这些都是后话了,此处略去不表了。

如下实现了周期性轮询状态变化,如果有变化则发送邮件,但是邮件不像即时消息那样立刻通知相应的人,如何能够做到发邮件后就能立刻收到提醒呢?由于目前已经是移动互联网应用如此普及的年代了,有如下两种方法可以参考:

  • 下载手机QQ邮件客户端,可以进行即时邮件提醒。
  • 使用QQ邮箱和微信绑定,关注邮件微信号,可以进行即时邮件提醒。

6   效果演示

最后让此程序运行了一段时间,对自己的博客和某个朋友的博客进行了监控。发现博客园的排名变化好久才进行更新,而且经常会是夜间或者是早上进行更新,下面是某天早上8点多的时候,收到的排名变化的提醒(由微信推送的邮件到达的提醒):

7   总结与展望

其实上面介绍的就是一个最简单的自动化监控和提醒工具的实现方式。这些思想和技术手段被广泛的应用于服务器接口监控,数据库连接监控,服务器运行状态监控等等。进行博客排名的监控只是一个好玩的小应用而已。

OK,介绍完毕,如果大家觉得有意思,或者有帮助,请点击博客下面的 推荐 ,谢谢了。


作者: Harmo哈莫
作者介绍: https://zhengwh.github.io
技术博客: http://www.cnblogs.com/beer
Email: dreamzsm@gmail.com
QQ: 1295351490
时间: 2015-10
版权声明: 欢迎以学习交流为目的读者随意转载,但是请 【注明出处】
支持本文: 如果文章对您有启发,可以点击博客右下角的按钮进行 【推荐】
posted @ 2015-11-17 22:48  一点一滴的Beer  阅读(8445)  评论(16编辑  收藏  举报