不久前,我曾經有寫過這篇[突發專案] 創作懶懶病良藥?|試寫 Vocus 最後文章發布時間計數器,一個可以計算出距離自己最後發文時間,已經過了多久的小工具。
當時是希望藉著這個數據化呈現,來督促自己持續產出,不過自從完成了之後,我也同時開始思考,該如何讓這個小工具出現在更多、更顯眼的地方,又或是加上其他資訊,讓它成為一個展示成就,同時又能激勵的工具?
於是,我鍵盤上的手,再度動了起來。
仔細想想,除了上次專案中數據化的發文時間計數外,其他能夠增進自己持續寫作慾望的,大概也就是持續累積的文章數,以及追蹤數了吧?
這麼一說,好像也曾經看到不少影音創作者們,會在桌前擺設一個即時的訂閱數計數器,就算是作為裝飾也是頗為酷炫。
而我們雖然暫時不完硬體,但如果想辦法把這些資訊整合一下,以最簡便的方式做成一個小工具,放到日常使用的手機上,似乎也是個不錯的製作方向。
不如這次就來試著抓取這些資料吧!
決定好目標,接著就來看要從哪裡取得資訊囉。
其實這次要抓的資料並不難找,因為這些資訊目前都能直接從方格子的個人頁面上找到,不過為什麼我要特別強調『目前』呢?
因為不同於上次使用的 RSS Feed 分析,這次要使用爬蟲的方法來抓取所需的內容,而這種方法的最大缺點,就是只要網頁一改版,就有極大的機率會失去效用。
不過,在沒有直接取得方法的情況下,還是暫時這樣處理吧。
接著就是寫程式時間拉,這裡要用的同樣是老朋友 Python 為撰寫語言,而在套件部分主要會用到的,也是網頁爬蟲常見的老班底們,那就直接進入正題吧!
首先我們要透過『request』模組,用程式化的方式模擬向伺服器取得網頁的原始資料,接著使用『BeautifulSoup』來解析取回的內容,並且抓出所需的欄位數字,因此程式碼大致如下。
import requests
from bs4 import BeautifulSoup
# User ID
user = "USER_ID"
# Request Information From URL
r = requests.get("https://vocus.cc/user/"+user)
# Parse Page
soup = BeautifulSoup(r.text,"html.parser")
接著回到瀏覽器來,看看方格子的個人專頁,以 Google Chrome 為例,先按下鍵盤上的『F12』鍵叫出開發者工具。
這裡需要先找到要抓的資料,在網頁原始碼中的位置,而在這次專案所需要的內容,主要就是資訊列這牌所顯示的數字,因此只要用瀏覽器的元素選擇工具就能快速定位。
由這裡可以看到,我們所需要的幾個欄位,都是位於『unit』及『bold』這兩個 Class 的 DIV 容器中。
在接下來的程式中,我們需要使用『soup.select』來抓取『div.unit』與『div.bold』這兩個項目,而在程式中加了如下這行後,我們基本上就能把相關的欄位資訊抓出來囉。
result = soup.select("div.unit,div.bold")
以防萬一,先來在 Jupyter 中測試執行一下,看看抓到的是不是我們要的內容。
嗯,看來是沒什麼問題,這裡抓出來的『result』內容,是由 BeautifulSoup 物件所組成的列表格式,所以可以使用迴圈的方式,一個一個叫來另外處理。
在迴圈裡面,我們針對每個物件使用『.text』這個後綴叫出每個 Class 中所包含的文字,從預覽中可以看到成功分離出來的標題與統計數值。
接下來,就是要進行項目的過濾跟建立字典啦!
從叫出來的預覽可以看到,整個列表的規律大致是『空值->統計->項目名』三樣為一組。
因此這裡就以空值為分界,並在抓到個別名稱及數值時,分別進配對儲存,最後集合成一個字典形式,於是就得到如下的程式。
## For Final Information Pack
buf = {}
num = None # Value Count
tit = None # Item Title
## Loop Through Result
for res in result:
# Get Text
inf = res.text
if not inf:
# If is Empty than Reset Value
num = None
tit = None
elif inf.isdigit():
# If Value is Digit, than Save as Count
num = inf
else:
# Else if Not Digit, than Save as Title
tit = inf
# If Both tit and num Have Value, than Save in Dict
if tit and num:
buf[tit] = num
else:
pass
最後把結果印出來看看吧!
看起來不錯,這樣基本資料取得作業就完成了,不過好戲還在後頭呢。
接下來就要把這隻爬蟲做些整合,這樣才能完成我們的大業(?)
為了讓前面寫的這個工具能夠隨時存取,就必須為它建立一個 API 服務。
我這裡們使用的是『Flask』這個套件,來提供架設伺服器的基本框架,同時建立一個連線接口可以觸發前面寫的爬蟲,並把抓到的資訊轉換成 Json 格式回傳,基本的程式碼如下。
# Import Basic Package for Setting up Web Server
from flask import Flask, jsonify
from waitress import serve
## Init Flask APP
app = Flask(__name__)
## Return API
@app.route('/vocu')
def repl():
# Set User ID
user = "mercteria"
# Function For Fetching Information Form Vocus
res = chkvoc(user)
# Return Result as Json
return jsonify(res)
## Start Server
if __name__ == "__main__":
print("Start Server")
# Set Debug Mod Off
app.debug = False
# Use Waitress Serve for Production Hosting
serve(app, host="0.0.0.0", port=3000) # Set Port to 3000
這裡是假設大家已經將前面的爬蟲,用 def 包好成一個名為『chkvoc』的功能,可以輸入使用者 ID 來做查詢,並指定『vocu』為連結網址。
修改完後就可以測試執行,成功啟動後,打開瀏覽器輸入『localhost:3000/vocu』應該就可以看到爬到的結果囉。
接下來的步驟,由於會牽涉到伺服器部署,並非每個人都有現成資源可以進行,因此可以單純作為參考即可。
作為示範,這裡我們直接使用『Ngrok』這個暫時性的工具來建立我們的服務,可以直接到這裡下載。
完成後輸入以下指令來啟動,這裡是以 Windows 系統為例,不同作業系統各有些許差異,可以至 Ngrok 官網查詢。
ngrok.exe http 3000
指令中最後的數字 3000 為前面設定好的 Flask 伺服器 Port。
接著就會進到這樣的畫面,畫面中『Forwarding』這行『.ngrok.io』結尾的網址,就可以連到我們的 Flask 服務囉。
直接到瀏覽器上測試,確認回傳一切正常後,就可以進到下一步了。
接下來,就要開始建立介面拉!
我們將作業環境移駕到手機上,首先要下載『Widgy』這款可以自己建立桌面工具的 APP。
這是一款應用十分多樣的 APP,除了 iOS ㄧ般的桌面 Widget 外,還能建立鎖定畫面工具,甚至是 Apple Watch 錶面,功能十分強大。
初次開啟 APP 時,會需要做ㄧ些基本的設定流程,這裡就不贅述,直接進到主畫面中。
首先在下方標籤點到『建立』欄位後,點一下最上方的『+ Create New』就可以開始製作。
可以看到他有提供不同樣式的小工具可以選擇,基本上 iOS 中支援的類型都可以製作,這裡就選擇基本的『小比例』作為模板。
進到編輯畫面後,在新增選項中選擇『文字』圖層。
接著點到最右側『資料』的項目,並點一下第一個『自訂文字』。
接著從列表中選擇『JSON 端點 → 端點』來進行設定。
接下來我們在前一個步驟取得的 Ngrok 網址就派上用場了,這裡直接將資料源頭的網址更換成我們自己的,然後按下執行。
接著他就會自動嘗試抓取資料,看到爬蟲回傳的資訊內容後,就代表成功了。
這裡假設要新增『篇文章』這個項目,就從列表中點進去就能做詳細設定,接著按下右上角『測試』再次確認。
如果內容無誤,按下『似乎還不錯』就能完成設定囉。
以上就是基礎的設定流程,接下來就是發揮創意時間,這個 APP 可以很自由的編輯自己喜歡的 Widget 介面,慢慢把小工具裝飾成自己喜歡的樣子吧!
不過,製作完成後,還有最後一個步驟,才能把小工具放到桌面上。
這裡要先點到『管理』頁面,可以看到很多的『小工具槽』空間,我們要先把剛剛製作完成的工具設定到其中一個後,才能在系統新增小工具的畫面選擇。
註:免費版能使用的格數會有限制。
這邊我將之前做好的放在第四格的位置,紅色的那個方塊,接著到 iOS 的桌面編輯,就能在對應的格數選到囉。
最後擺放到喜歡的位置,就大功告成啦!
最後順帶提醒,由於上面的伺服器,僅是為了示範而臨時架設,並非長久使用之計,如果想要持續使用的話,最好還是另外租用雲端運算主機會比較妥當喔。
另外,雖然在這次範例中只有提到基本資料的抓取,但還是可以自行跟上一篇的日期計算做整合,只要有包含在回傳的資料中就可以了。
完結撒花!
嗯⋯再一次的手癢後,似乎又完成了一個稍微意義不明的專案了呢。
我想,玩 Side Project 的心情大概就是這樣吧,有些時候就只為了小小目標,而大費周章的繞一大圈。
甚至於只是想滿足一個「因為我可以」的心情,不過或許也是因為這樣,才有完成它的趣味存在。
不知道下一次,又會冒出什麼莫名的靈感呢?
《全文。終了》