這次大選資料整理,個人做得比較不激情(跟其他家相比應該是太不認真&深入),但還是記錄一筆資料整理的方式。實際成品:
真的!不搶快、沒灌票,這次嘗試的是:
1. 接到中選會的資料
2. 比對選區資料、參選人號次資料
3. 產出圖表需要的json
4. 丟上雲端供前端工程師吃吃
操作與程式流程
這一次大部分的程式都在python裡,考量是因為中選會三分鐘會更新一次資料,如果跟九合一選舉一樣大多用Spreadsheet當作編輯的中間層的話,怕更新速度不夠快(python寫資料進Spreadsheet的API速度很慢),所以這次比對資料不是用Spreadsheet公式,用python pandas處理對表與篩選。
中選會資料
要即時資料要跟中選會申請,過了會得到一個程式跟帳密,打開以後每三分鐘就會存一個json到本機。
json資料處理
json到手以後,是要對什麼呢?舉雙帥對決的中山北松山為例,中選會的資料裡這區參選人得票記在這個list裡,沒有人名、沒有黨籍:
[{'candNo': 1, 'tks': 5730, 'candVictor': ' ', 'tksRate': 2.6133}, {'candNo': 2, 'tks': 99539, 'candVictor': ' ', 'tksRate': 45.3973}, {'candNo': 3, 'tks': 1209, 'candVictor': ' ', 'tksRate': 0.5514}, {'candNo': 4, 'tks': 112784, 'candVictor': '*', 'tksRate': 51.438}]
人名、黨籍在資訊呈現上是必須要素,而依設計要在地圖呈現顏色也需要判斷給色,所以我做出這樣的資料:
[{'candNo': 4, 'candVictor': '*', 'color': '#9FB7D6', 'color_end': '#2A60A5', 'name': '蔣萬安', 'party': '中國國民黨', 'tks': 112784, 'tksRate': 51.438},
{'candNo': 2, 'candVictor': ' ', 'color': '#8CD8D2', 'color_end': '#00A89C', 'name': '吳怡農', 'party': '民主進步黨', 'tks': 99539, 'tksRate': 45.3973},
{'candNo': 1, 'candVictor': ' ', 'color': '#9DE6E6', 'color_end': '#26C9C8', 'name': '何景榮', 'party': '台灣民眾黨', 'tks': 5730, 'tksRate': 2.6133},
{'candNo': 3, 'candVictor': ' ', 'color': '#C2C3C5', 'color_end': '#777A7F', 'name': '田方宇', 'party': '安定力量', 'tks': 1209, 'tksRate': 0.5514}]
每位參選人都加上了姓名、黨籍、開票中的色碼、勝選後的色碼,還以得票數高排序。單一選區的資料是這樣(還有選區名稱、svg id、開票進度、勝選者、對應色碼、參選人數等):
把資料對上去的過程大致是:以prvCityArea當成key值,合併預備好的選區地理資料、參選人基本資料、自行宣布當選資料:
(很直覺地就用了pandas來處理這些事情,沒有想過用、也沒有試過其他dict的處理法,感覺要走很多迴圈?)
前端工程師再把資料塞進地圖與表格裡,這幾筆資料大概是這個地圖位置:
這次一共有總統票比例、總統票版圖、區域立委票、區域立委版圖、區域立委席次、政黨票、當選名單要出json,處理模式都差不多。
少少地用到Spreadsheet的部分
上圖圖面上有個當選戳記,而中選會資料裡有個candVictor,我製作的表格裡有個winner,關係是?winner是由編輯標記的資料。
原因在於中選會報票速度不快大家都知道,大部分自行宣布當選速度超快,像是本次第一名金門陳玉珍宣布當選的時候,台北市的開票進度還不到1%呢。所以票數是中選會的,當選者是編輯勾選的資料加進程式裡。這次用的Spreadsheet公式:
這次處理這份當選名單對表不是用vlookup了,改用filter(用熟還挺不錯好用的一個公式喔)因為每個選區的候選人不一樣多,每一行指定範圍很麻煩。A欄基本上就是key值,以這個先篩出選區,再篩當選註記。
丟檔案上Google Storage
Spreadsheet表格用google apps script丟上google storage…使用了網路上寫好的Library,做幾個設定、換service account credential,就可以上傳了。以下這兩篇文章:
用GAS把Spreadsheet資料轉為json丟上Google Storage這個方式已經用幾個月了,但這次發現個問題:Google Cloud Storage對於高頻率更新、呼叫資料似乎是有限制,程式執行一陣子後部分人load不進新資料,再跟cache的問題混在一起,簡直就是逼人長白髮。
而且在尾聲發生一件奇怪的事,更新完不分區名單之後,網頁上一直沒有出現,我說:我這裡看json有資料了哇,工程師說:陣列是空的哇。
兩個人在那裡哇哇哇,後來發現http版本有新資料,但是https版本沒有…過一陣子之後才出現…在測試時完全沒發生的狀況,正式開票時卻跑出來讓人嚇得屁滾尿流。(這次有開程式測試幾天,沒有發現類似問題,選後也還沒去查明)
python要上傳Google Storage有裝package就方便許多,這樣就可以做到:
幾個雷坑
- 檔案3分鐘更新一次,雖然進行中的檔案約莫2MB,雖然中選會的程式介面已經看到有檔案了,但其實還沒跑完,這時候讀取json就出錯,測試的時候4個小時裡可能發生一次,就沒有特別寫例外,正式上場的時候爆炸10幾次吧,整個步調都亂掉了
- 中選會的選區資料有錯,像是旗津沒靠海、鳳山在海邊;板橋西區在板橋東區左邊之類的問題,真的要全部檢查過。
- 用google storage是不是個好方法,未來可以再多試一些。像天下這篇有提到GAS gsheet api,但最終仍是排程上GSC…可能我有漏掉什麼吧,要再摸熟點。
天佑台灣。