Zerojudge stats
動機
繼上篇如何打造好看的Github Profile,就是看到許多大佬的GH首頁都很炫炮的統計紀錄!
又翻了翻GH,發現各大解題平台如:leetcode、codeforce(但我覺得沒有到很好看)、TIOJ等都有人做過專門放在GH首頁好看的解題統計了
唯獨我刷最多水題的Zerojudge沒有
那只好自己做一個了(⊙ω⊙)
如何辦到的?
但是仔細看一下發現:Profile page竟然是一個README.md
,那他們是怎麼在靜態的頁面顯示即時的資料的?
接著看一下他們的raw markdown,可以看到那些統計紀錄都是一個個圖片,而圖片的src
則是連到某個網站的url
。
如:這個可以顯示在Github活動狀態的project
他的使用方法:

大概揣摩一下,應該是:
當瀏覽者訪問作者頁面時,將上面的url
當作圖片source,並且透過GET
parameter來查詢用戶資料或指定主題。而他的server在收到request後,就向Github查詢用戶資料再包成一個SVG
顯示在頁面上,並且頁面的content-type
要指定為SVG
(這樣才能當成圖檔來用)。
為什麼Zerojudge沒有人做?
我猜想應該是:
- Zerojudge需要登入才能查詢用戶資料 如:leetcode、TIOJ不需要登入,而codeforce則是提供API查詢
- Zerojudge的登入方式
目前ZJ的登入方式有兩種:
- 通過
recaptcha 2
驗證(防機器人ㄉ那個驗證) - 登入google帳戶
- 通過
大佬都不想寫Zerojudge(畢竟題目太雜了)
而要讓server登入Zerojudge並讓某一個帳號持續維持登入狀態是最大的困難點
整體架構概念
所以我要先搭建一個app能夠即時查詢Zerojudge的資料,並將統計資料包成SVG回傳,還有要能夠方便地登入Zerojudge並維持登入狀態。
又因為比起PHP(我還沒學過)、Javascript(我沒有學過他的後端,也比較不熟悉它的語法)、Ruby(也沒學過)等我比較熟悉Python
所以就用flask來寫這個專案的後端
登入Zerojudge
通過recaptcha驗證
目前要破解recaptcha最有效率的方式是透過音檔辨識(畢竟圖像辨識的技術沒有到音檔辨識那麼精準?而且還需要額外訓練一個模型才有辦法)
音檔辨識的python library有SpeechRecognition
(它可以接到Google Cloud Speech API,算是以其人之道,還治其人之身)
登入google帳號
要透過python登入google帳號,我有試過beautifulsoup 4
但是一直會有bug..
另一種方式是透過selenium + webdriver(可以算是透過程式操控一個瀏覽器)但是也很容易被擋
嗯…
這兩個方式都會需要將webdriver塞到server裡面,登入方式算是透過程式操控一個瀏覽器然後在指定的位置按按鈕、送出張號密碼來登入
我覺的這個這兩種方法都笨笨ㄉ而且效率也不高,但是在構思階段也沒有想到什麼好方法
靈光一閃
突然想到:當一個帳號登入到Zerojudge時,會產生一個JSESSIONID
並且發出request時只需要改變header
的JSESSIONID
就能以該登入帳號的身份進入網站。
那代表:我只要拿一個帳號作為專門向Zerojudge查詢使用者資料的帳號,並且我可以在自己的電腦登入該查詢帳號再將JSESSIONID
傳到我的app中,就可以讓我的server以登入帳號的身份發出request!
實做
工具:
-
Flask、Flask login (後端server)
-
beautiful soup 4 (解析向ZJ的request,擷取關鍵的解題數)
-
手刻
SVG
(那時候沒有找到什麼很好用的SVG online editor) -
boostwrap 5(因為手刻
css
、js
並沒有比較好看…)
為什麼不用Node.js
、PHP
、rust
…
因為我對python比較熟w
必要功能:
-
登入界面 (for Admin user)
-
Admin 界面 (讓我更改
JSSESSIONID
) -
GET
回應點 (透過query parameter
傳用戶id、主題…然後給好看的badge回來)
困難:
大致的架構都寫好後,在最關鍵的將圖片顯示在瀏覽者頁面
有問題
我先將SVG
的架構寫成模板,只要將用戶的name、解題數套入就可以生成新的圖片
然而要將GET回應點
顯示的SVG
的content-type
改成image
相關的才有辦法讓瀏覽器以該url的回應點當成圖片的source
(我那時候不知道,又因為render_templates()
的預設content-type
都是html
,所以我在localhost
試了幾百遍還是沒有辦法將看的到的圖片
當成圖檔
來用…)
我看了Flask的document還是沒有找到解法(其實是技術知識不夠,那時候我還不知道mime type
的相關知識,所以將content-type
改成image
就可以解決了,但是我大概卡了兩天…
最後的解決方法:
只好厚臉皮的去Stackoverflow
問問題
部署app:
Heroku
免費的真香!
Heroku就是最簡單可以部屬app的serverless雲端服務,它提供每個月500小時的免費時數(但是大概算一下就發現30×24=720 > 500 ,它提供的免費時數不足夠讓你的server一整天都是開機的狀態)
而且他的主機在美國,也就是在瀏覽者頁面顯示前,必須在台灣與美國經過四次來回!(Zerojudge的主機應該也在台灣吧?
清況如下:
大概這種感覺
-
瀏覽者(Taiwan)→(瀏覽器加載圖片,
GET
我的app)→ -
我的app(USA)→(向ZJ查詢用戶解題統計)→
-
ZJ(Taiwan)→(回應請求,回傳給app)→
-
我的app(USA)→(將資料包成SVG圖檔回喘給使用者)→
-
瀏覽者(Taiwan)在瀏覽器看到
Zerojudge stats
這樣造成嚴重的延遲,很常就runtime error了(而且應該不適合設定CDN
,畢竟是要查詢即時的資料,預先加載到附近網路交換點很像沒什麼用?
缺點:
- 延遲
不用多說ㄌ
- 程式穩地性
目前還是Beta版本,很常app就掛掉…還有許多細節可以調整!
- 網頁暫存
跟同學測試後發現有這個問題,但也不知道要怎麼解決。
畢竟瀏覽器為了加載速度會將曾經訪問過的資料暫存起來,那該使用者可能看到的還是舊的圖檔…
改進&加強:
目前想到的解決方案如下:
- Google Cloud Platform
可是在GCP弄一個server只為了,部屬類似API功能的app感覺有點浪費?
- 自己架server
技術門檻高,還有供電、網路…要考慮
- 在台灣有主機的cloud server
品質一定沒問題的只有GCP,其他太便宜的不敢用
- Google app script
目前還在研究,主要透過JS來寫,但是這還是比較適合跟Google提供的app做互動。目前遇到的問題的向其他網站request的時候沒辦法改header中的Cookie
- Worker
3/26更新,湊巧在查為什麼那麼多人的subdomain都是worker.dev
看起來超帥?大概了解一下才知道:worker
是cloudflare
提供的serverless服務,但是完全支持的語言只有Javascript
、Typescript
(不過官方說也可以將python
、PHP
…編譯成Javascript,細節還需要再研究一下)