JSON

學完了怎麼開關編輯檔案,這裡介紹一個常見的資料格式,許多程式的資料庫或資料顯示方式都是 JSON

JSON 是 JavaScript Object Notation 的簡稱,JavaScript 是目前最普遍的寫網頁用的語言,object notation 就是指在 JavaScript 這個語言裡,object 的形式幾乎就是 JSON 的形狀。許多網頁資料庫就是用 JSON 寫。
而很幸運地,Python 要處理 JSON 也非常容易。

json官網在這

簡單來說,json 就是一個大 dictionary。
複雜來說,它是一個 a format of strings,一個裝了無限個 dictionary 和 list 的 dictionary。


For example,

以下是一個 json 檔實際運用的例子,在我的疫情bot裡,許多功能都會需要每日確診的資料,因為每一次需要資料時都重新上網抓很麻煩,所以我們決定把資料一次抓下來,讓需要用到的地方讀我們自己的資料庫就好

{
    "today_confirmed": 0,
    "today_domestic": 0,
    "today_imported": 0,
    "today_deaths": "26",
    "additional_text": "\n今日新增之16,524例本土病例",
    "error": false
}

可以看到最外層是一組大括號,跟 dictionary 一樣
裡面也是一個 key 加 一個 value,跟 dictionary 一樣

下面是另一個我的疫情bot有用到的 json,這一個檔名叫 history_data.json,用來製作統計圖表的。
因為程式每天都會被重新跑一次,所以前一天的資料沒有辦法只存在程式記憶體 也就是任何 variable 裡,於是我們用一個外部的檔案作為資料庫。

{
    "confirmed": [
        50, 25, 50, 25, 55187, 94808, 0, 0, 10000, 8822, 49, 0, 1000, 104
    ],
    "average": [
        21449, 21442, 22867, 24120, 24123, 16239, 2838, 2853, 2996, 1582, 326, 320, 323, 187
    ],
    "dates": [
        "1015", "1014", "1013", "1012", "1011", "1010", "1009", "1008", "1007", "1006", "1005", "1004", "1003", "1002"
    ]
}

可以看到最外依然是 dictionary 的起手勢,但比較特別的是,這次的 value 是一個 list


Step by step

有基礎的概念之後,使用方式跟一般的 Python file I/O 差不多,只是我們可以用 Python 的 json library 來方便控制每一項

以上面的 histiry_data.json 為例
讀檔會跟一般讀檔一樣

import json

with open("history_data.json", "r") as jsonFile1:
    history = json.load(jsonFile1)

這裡 with open("history_data.json", "r") as jsonFile1jsonFile1 = open("history_data.json", "r") 一樣,差別是後者最後需要 jsonFile1.close() 而前者不用。
接著 json.load(jsonFile1) 叫了一開始 import 進來的 json module,並使用了它的 load() function,最後這個 function 的 return 是一個 Python 看得懂的 json 格式,我們把它塞進一個名為 hostory 的 variable。
從這一刻起,hisotry 就不是一般讀檔讀進來的一堆純文字,而是一個 Python 的 json object

Python 對於 json 最友善的部份就是我們完全可以把讀進來的 json 檔當作 dictionary 用

confirmed_history_list = history["confirmed"]
average_history_list = history["average"]
dates_history_list = history["dates"]

就像用 key 讀取 dict 的 value 一樣,上面讀了 confirmed 和 average 這兩個 key 的 value,這兩個 value 不是單一數值而是一個 list,但仍然可以分別塞近 variable 裡,變成一般的 list

接著繼續

confirmed_history_list.pop()
average_history_list.pop()
dates_history_list.pop()
#--------------------------------------
confirmed_history_list.insert(0, today_confirmed)

today_average = int(statistics.mean(confirmed_history_list[:7]))
average_history_list.insert(0, today_average)

dates_history_list.insert(0, today_date)

上面第一部份是簡單地把 list 的最後一項刪除
第二部份用了 Python list 的 insert() function (也是我當下搜尋才知道有這個東西),憑直覺地,可以看出 insert() 這個 funciton 的第一個 argument 應該代表想要插入的 index,而第二個代表想插入的值
於是這一段我把 list 的尾巴刪掉,從頭補了新的一項進去
也就是把當天的資料加入資料庫,然後把超過兩星期的過時資料刪掉了

但到目前為止 confirmed_history_list, average_history_list, 和 dates_history_list 都是我的 variable,與我的檔案無關,所以還需要把這些更新後的資料重新寫入檔案內

history["confirmed"] = confirmed_history_list
history["average"] = average_history_list
history["dates"] = dates_history_list


with open("history_data.json", "w", encoding='utf-8') as jsonFile2:
    json.dump(history, jsonFile2, indent=4)

上半部我們借用之前的 history 這個 json object,覆蓋掉它原本的值,把原本 key 是 confirmed, average, 和 dates 的 value 換成新的、改過的 list
下半部我們重開了一個可以寫入的 stream,然後用 json 的 dump() function 把更新後的 json object 整包塞到檔案

這就是說基礎不基礎,說複雜不複雜的 json 基本用法~


實際運用

這裡是一個政府的開放資訊平台的資訊
https://data.gov.tw/dataset/156914
很多(或大部分)的個人 project 都會用到各種政府開放資訊,常見的格式有 txt, json, 和 csv,我個人最喜歡的格式就是 json。
現在可以來玩玩看開放資訊囉

by json王 XD