zoukankan      html  css  js  c++  java
  • 查看博客园积分与排名趋势图的工具

    问题的提出

    在博客园写文章有一段时间了,除了自己有一些新的发现想与别人分享外,推动我写文章的最大动力就是看博客园排名不断增长啦!然而在博客园后台,只能看到当天的积分与排名,历史值和趋势却没有办法查询,对于文章发表后对自己积分与排名的影响并不直观,于是就想到自己动手做一个积分与排名趋势图这样一个工具。

    具体步骤

    1. 打开博客园积分与排名显示

    这个就不消多说了,在博客园后台,选项->控件显示设置中,将积分与排名勾选并保存。

    刷新页面后,可以在侧边栏看到自己博客的积分与排名:

    2. 使用 curl 在本地获取当天信息

    为了获取当天的积分与排名,需要使用 curl 下载页面。

    curl -s 'https://www.cnblogs.com/goodcitizen/ajax/sidecolumn.aspx'

    为什么是这个页面,而不是主页,我也不清楚,我是从附录 1 得到的启发。输出比较多,只看我们关心的部分

    可以看到积分是在名为 liScore 的 html 元素中,排名是在 liRank,没有找到解析 html 的趁手命令,直接使用 grep + sed 搞起

    curl -s 'https://www.cnblogs.com/goodcitizen/ajax/sidecolumn.aspx' | grep 'liScore' -A 6 | sed -n -e 3p -e 7p

    这句话后半段翻译一下就是,取看到 liScore 关键字所在行(含)的后面 6 行,积分与排名的值分别位于第 3 行、第 7 行,使用 sed 过滤这两行,就成这样了

    4709
    113450

    完整的脚本如下

    score.sh

     1 #! /bin/sh
     2 git pull origin master
     3 day=$(date +"%Y-%m-%d")
     4 last=$(cat ./score.txt | tail -1 | awk '{ print $1 }')
     5 if [[ "$day" < "$last" ]] || [[ "$day" = "$last" ]]; then
     6     echo "has updated, skip"
     7     exit 0
     8 fi
     9 
    10 data=$(curl -s 'https://www.cnblogs.com/goodcitizen/ajax/sidecolumn.aspx' | grep 'liScore' -A 6 | sed -n -e 3p -e 7p)
    11 score=$(echo $data | sed -n 1p)
    12 rank=$(echo $data | sed -n 2p)
    13 echo "$day $score $rank" >> score.txt
    14 git add score.txt
    15 git commit -m "udpate score"
    16 git push origin master

    增加的部分主要是

    1. 添加日期列作为横轴 (line 3,13)
    2. 将当天信息作为一行追加到 score.txt 文件 (line 11-13)
    3. 添加当天信息前判断是否已经记录过,如果是则跳过,防止重复添加 (line 4-8)
    4. 将修改后的 score.txt 文件上传到 github (line 14-16)

    3. 使用定时任务记录每天的信息

    经过长时间的暗中观察,我发现博客园的积分与排名是每天更新一次。于是我们可以增加一个定时任务,每天中午跑一下,来获取当天的信息。不同的系统,方法不一,下面分别说明

    3.1 计划任务 (Windows)

    什么,你这个不是 shell 脚本吗,怎么还能在 Windows 上跑?嘿嘿,不错。上面的例子我就是运行在 Windows 上的,因为我装了一个 git bash,它自带 msys2 环境,类似于 mingw,也是一种在 Windows 上运行的 Linux 微环境,一些常用的 Linux 命令都支持的,例如上面说到的 grep、sed、git,并且可以直接跑 shell 脚本。如果是这样,在 windows 上的定时任务非‘任务计划’莫属了,下面就是我创建的任务截图

    我设置在了每天中午 12:00 运行,下面这个文件是可以直接导入的那种

    <?xml version="1.0" encoding="UTF-16"?>
    <Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
      <RegistrationInfo>
        <Date>2020-06-17T10:26:43.9929008</Date>
        <Author>GRANDSOFTyunh</Author>
        <Description>auto record blog score &amp; rank</Description>
        <URI>log_score</URI>
      </RegistrationInfo>
      <Triggers>
        <CalendarTrigger>
          <StartBoundary>2020-06-17T12:00:00</StartBoundary>
          <Enabled>true</Enabled>
          <ScheduleByDay>
            <DaysInterval>1</DaysInterval>
          </ScheduleByDay>
        </CalendarTrigger>
      </Triggers>
      <Principals>
        <Principal id="Author">
          <UserId>S-1-5-21-436374069-1957994488-1801674531-58720</UserId>
          <LogonType>InteractiveToken</LogonType>
          <RunLevel>LeastPrivilege</RunLevel>
        </Principal>
      </Principals>
      <Settings>
        <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
        <DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
        <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
        <AllowHardTerminate>true</AllowHardTerminate>
        <StartWhenAvailable>false</StartWhenAvailable>
        <RunOnlyIfNetworkAvailable>true</RunOnlyIfNetworkAvailable>
        <IdleSettings>
          <StopOnIdleEnd>true</StopOnIdleEnd>
          <RestartOnIdle>false</RestartOnIdle>
        </IdleSettings>
        <AllowStartOnDemand>true</AllowStartOnDemand>
        <Enabled>true</Enabled>
        <Hidden>false</Hidden>
        <RunOnlyIfIdle>false</RunOnlyIfIdle>
        <WakeToRun>false</WakeToRun>
        <ExecutionTimeLimit>PT72H</ExecutionTimeLimit>
        <Priority>7</Priority>
      </Settings>
      <Actions Context="Author">
        <Exec>
          <Command>E:codecnblogsscore.sh</Command>
          <WorkingDirectory>E:codecnblogs</WorkingDirectory>
        </Exec>
      </Actions>
    </Task>

    注意运行脚本的目录,最好是 github 的检出目录,这样 git 相关的命令才可以正常工作。git 检出地址可以点这里

    3.2 crontable (Linux)

    Linux 原生的 crontable 很擅长这类定时任务,直接输入下面的命令就可以了:

    $ crontab
    * * * * * /home/yunhai/code/cnblogs/score.sh

    这样就可以每分钟执行一次 score.sh 脚本了。从日志看定时任务执行过了

    $ sudo tail -f /var/log/cron
    Jun 28 02:23:33 localhost crontab[7389]: (yunhai) REPLACE (yunhai)
    Jun 28 02:23:37 localhost crontab[7391]: (yunhai) LIST (yunhai)
    Jun 28 02:24:01 localhost crontab[7394]: (yunhai) BEGIN EDIT (yunhai)
    Jun 28 02:24:01 localhost CROND[7399]: (yunhai) CMD (/home/yunhai/code/cnblogs/score.sh)

    但是为什么本地 score.txt 没有更新呢?经过一番探究,原来它生成到了用户的 HOME 目录 (/home/yunhai) 下面。好吧,需要做一点修改

    $ crontab -e
    0 12 * * * cd /home/yunhai/code/cnblogs/; /home/yunhai/code/cnblogs/score.sh

    执行命令前先切换工作目录,这回可以正常工作了。同时修改运行间隔为每天中午 12:00。

    3.3 数据样例

     经过几天的积累,我收集到一些数据

    2020-06-17 4456 116048 
    2020-06-18 4456 116048 
    2020-06-19 4531 115156 
    2020-06-20 4621 114051 
    2020-06-21 4639 113908 
    2020-06-22 4654 113803 
    2020-06-23 4666 113741 
    2020-06-24 4682 113606 
    2020-06-25 4692 113558 
    2020-06-26 4692 113558 
    2020-06-27 4702 113488 
    2020-06-28 4709 113450 

    4. 使用 gnuplot 绘制趋势图

    有数据以后,就该通过图表呈现了,这个任务是通过 gnuplot 工具完成的。首先在我的测试环境(CentOS 6.7)上安装 gnuplot

    $ sudo yum install gnuplot
    $ gnuplot --version
    gnuplot 4.2 patchlevel 6 

    没有在 Windows 上的 git bash 里折腾 pacman,所以这一步目前只能在 Linux 上进行。

    4.1 最基本的实现

    之前没用过 gnuplot,参考附录 2 ,先用最简单的语句画一个草图出来

    draw.plt

     1 #! /usr/bin/gnuplot
     2 set terminal png size 1080,720
     3 set title "cnblogs/goodcitizen"
     4 set output "draw.png"
     5 
     6 set xlabel "day(s)"
     7 set ylabel "score"
     8 set grid
     9 plot "score.txt" using 1:2 w lp pt 5 title "score", "score.txt" using 1:3 w lp pt 5 title "rank"
    10 quit

    得到下面的效果

    看起来不太理想,主要是横轴都挤在一起了

    4.2 时间横轴

    根据附录 3 ,可以让 gnuplot 识别日期,修改一下脚本(增加 6-8 行)

     1 #! /usr/bin/gnuplot
     2 set terminal png size 1080,720
     3 set title "cnblogs/goodcitizen"
     4 set output "draw.png"
     5 
     6 set xdata time
     7 set timefmt "%Y-%m-%d"
     8 set format x "%m/%d"
     9 
    10 set xlabel "day(s)"
    11 set ylabel "score"
    12 set grid
    13 plot "score.txt" using 1:2 w lp pt 5 title "score", "score.txt" using 1:3 w lp pt 5 title "rank"
    14 quit

    得到这样的效果

    时间轴没问题了,现在主要是同时在一张图表上显示 score 与 rank,而它们取值范围差别较大,共用一个纵轴有点被压扁的感觉。

    4.3 绘制多图

    参考附录 4 ,给出的解决方案是绘制多个子图,分别进行展示

     1 #! /usr/bin/gnuplot
     2 set terminal png size 1080,720
     3 set title "cnblogs/goodcitizen"
     4 set output "goodcitizen.png"
     5 set grid
     6 
     7 set xdata time
     8 set timefmt "%Y-%m-%d"
     9 set format x "%m/%d"
    10 set xlabel "day(s)"
    11 
    12 # multi-plot
    13 set size 1,1 # 总的大小
    14 set origin 0,0 # 总的起点
    15 set multiplot # 进入多图模式
    16 
    17 set size 0.5,0.5 # 第一幅图大小
    18 set origin 0,0.5 # 第一幅图起点
    19 set ylabel "score"  
    20 plot "score.txt" using 1:2 w lp pt 5 title "score"
    21 
    22 set size 0.5,0.5 # 第二幅图大小
    23 set origin 0.5,0.5 # 第二幅图起点
    24 set ylabel "rank"  
    25 plot "score.txt" using 1:3 w lp pt 7 title "rank" 
    26 
    27 unset multiplot
    28 quit

    主要是通过 set multiplot 及设置各子图位置、大小来绘制多个子图

    效果比之前好多了,但是不能将两条曲线对比着看,还是有点别扭。

    4.4 双纵轴

    附录 5 介绍了另外一种解决方案,它使用的是双纵轴,适用于共用横轴的多条曲线

     1 #! /usr/bin/gnuplot
     2 set terminal png size 1080,720
     3 set title "cnblogs/goodcitizen"
     4 set output "goodcitizen.png"
     5 set grid
     6 
     7 set xdata time
     8 set timefmt "%Y-%m-%d"
     9 set format x "%m/%d"
    10 
    11 set xlabel "day(s)"
    12 set ylabel "score"  
    13 set y2label "rank"
    14 set y2tics
    15 set ytics nomirror
    16 
    17 plot "score.txt" using 1:2 w lp pt 5 title "score" axis x1y1, "score.txt" using 1:3 w lp pt 7 title "rank" axis x1y2
    18 
    19 quit

    主要是通过启用第二条纵轴并在绘图时指定依赖坐标系实现的

     嗯,这下就比较直观了。

    5. 汇总

    有了上面 gnuplot 脚本,就可以直接用一个 shell 脚本搞定绘制与打开图片两个过程了:

    plot.sh

    1 #! /bin/sh
    2 gnuplot ./draw.plt
    3 eog draw.png &

    eog (eye of gnome) 是 CentOS 原生的命令行启动图片浏览工具的命令 (参考附录 7 ),在其它平台上不一定适用。这里使用后台打开的方式,避免用户不关闭图片、这个脚本就一直卡死的问题。

    结语

    制作了工具就是拿来用的,现在我们分析一下 6/17 至 8/10 的数据:

    可以从图上看出几点规律:

    1. 发表文章(6/17、7/14、7/28)后可以看到明显的积分上涨过程,一般情况下积分涨幅比较平稳;
    2. 在没有发表文章的情况下,工作日流量比周末要多,如果追求阅读量,那就尽量在工作日发表文章(几次‘横盘’都发生在周末);
    3. 10 W 名之外的积分基本上遵循:积分增长 * 10 = 排名前进,大概涨 100 积分,会让排名前进 1000 的规律;
    4. 10 W 名之外的排名很少有回落,即使积分不增长也是如此,但是再往前可能就不一样了,因为逆水行舟不进则退。

    为了能多涨点儿积分,本来已经刷完的 apue 我决定进行二刷,来多写点文章,可能这就是传说中的‘虚荣心’吧。

    下载

    代码都提交到了 github, 欢迎前来复刻

    https://github.com/goodpaperman/cnblogs

    为了方便大家切换到自己的博客,fork + clone 之后只需要修改下面的文件内容即可:

    user.txt

    goodcitizen

    将这个名称改为你自己的博客名,然后在本地建一个定时任务去跑那个脚本就可以了啦。这里面用到了向 gnuplot 脚本传递参数的方式,可以参考附录 6 。其实你也可以改成任意第三方的博客名,只要他开启了积分排名显示,就可以公开"偷窥"啦。

    最后补充一点就是,在 Windows 上也可以直接安装 gnuplot,将安装后 exe 所在路径(例如 E: oolsgnuplotin)添加到环境变量并重启系统后,git bash 也可以在 Windows 上访问 gnuplot 命令了!(除了不能直接打开图片,因为 eog 不能正常工作,可以换成 mspaint 工具),下面是在 Windows 上输出的效果:

    貌似着色不太一样,可能是我用的版本比 Linux 上面高一点,其它方面没什么差别。最后附录 8 提供了 gnuplot 的官网,可以从这里下载各种系统的预编译版本,附录 9 提供了中文手册,看起来比官网轻松一些。

    参考

    [1].WP 获取博客园积分,并以图表形式呈现变化趋势

    [2].Ubuntu环境下使用gnuplot由数据表绘制曲线图

    [3].利用 gnuplot 绘制时间序列图

    [4].谈谈gnuplot(三十四):多图(multiplot)

    [5].用gnuplot实现双纵坐标绘图

    [6].如何将命令行参数传递给gnuplot?

    [7].linux命令察看图片

    [8].gnuplot 官方网址

    [9].gnuplot 中文手册

  • 相关阅读:
    Spring 详解第三天
    Spring 详解第二天
    springmvc的运行流程分析
    Spring 详解第一天
    【Java面试题】40 你所知道的集合类都有哪些?主要方法?
    【Java面试题】39 Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?
    【Java面试题】38 Collection 和 Collections的区别
    【Java面试题】37 说出ArrayList,Vector, LinkedList的存储性能和特性
    【Java面试题】36 List、Map、Set三个接口,存取元素时,各有什么特点?
    【Java面试题】35 List, Set, Map是否继承自Collection接口?
  • 原文地址:https://www.cnblogs.com/goodcitizen/p/cnblogs_score_and_ranking_trend_chart.html
Copyright © 2011-2022 走看看