1. 程式人生 > >檢視部落格園積分與排名趨勢圖的工具

檢視部落格園積分與排名趨勢圖的工具

問題的提出

在部落格園寫文章有一段時間了,除了自己有一些新的發現想與別人分享外,推動我寫文章的最大動力就是看部落格園排名不斷增長啦!然而在部落格園後臺,只能看到當天的積分與排名,歷史值和趨勢卻沒有辦法查詢,對於文章發表後對自己積分與排名的影響並不直觀,於是就想到自己動手做一個積分與排名趨勢圖這樣一個工具。

具體步驟

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>GRANDSOFT\yunh</Author>
    <Description>auto record blog score &amp; rank</Description>
    <URI>\blog_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:\code\cnblogs\score.sh</Command>
      <WorkingDirectory>E:\code\cnblogs</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:\tools\gnuplot\bin)新增到環境變數並重啟系統後,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 中文