最近在整理 Python 網頁爬蟲筆記, 覺得有兩個內建模組很常用, 第一個是 csv 模組, csv 檔是 Excel 試算表的純文字版, csv 模組提供讀寫 csv 檔的函式可快速地將檔案內容轉成 Python 字典或串列, 用法參考 :
第二個是 json 模組, 這是 Python 用來處理 JSON 格式資料的內建模組, 與 csv 模組一樣, 直接匯入即可使用 :
import json
JSON (JavaScript Object Notation) 是一種結構化資料表示法, 源自 Javascript 的物件定義語法, 因為具有輕量與可讀性高的特性, 逐漸取代較複雜的 XML 成為最普及的 Web 資料交換格式, 也被許多程式語言支援, 很多 Web API 採用 JSON 格式來回傳, 很多 NoSQL 資料庫也以 JSON 來儲存資料, 參考 :
JSON 資料格式有兩種語法, 第一種是與 Python 字典類似, 由鍵值對組成的 Javascript 物件, 語法如下 :
{"key1": "value1", "key2": "value2", ........}
規則 :
- 鍵值對必須用大括號括起來, 每組鍵值對以逗號隔開
- 鍵 (key) 必須是字串, 且須使用雙引號括起來, 不可用單引號
- 值 (value) 可以是所有 Javascript 資料型態 : 數值, 字串, true/false, 陣列, null
- 物件內不可使用任何註解
- 交換資料時存成副檔名為 .json 檔案, 每一個 .json 檔只能含有一個物件
例如 :
{"name": "Tony", "gender": "male", "age": 26, "height": 172.5, "married": true, "religion": null}
第二種 JSON 資料表示法為 Javascript 陣列, 語法與 Python 串列一樣, 元素放在中括號裡面以逗號隔開, 可以是任何 Javascript 資料型態 :
[e1, e2, e3, ...]
例如 :
["Tony", "male", 26, 172.5, true, null]
不論是陣列或物件, 在一個 JSON 檔裡面只能有一個陣列或一個物件, 如果有多個物件, 可以將其放入一個陣列裡成為物件陣列, 例如 :
[{"name": "Tony", "gender": "male", "age": 26, "height": 172.5, "married": true, "religion": null},
{"name": "Jane", "gender": "female", "age": 22, "height": 167.2, "married": false, "religion": null}]
如果有多個陣列, 可以將其放入另一個陣列裡成為多維陣列, 例如 :
[["Tony", "male", 26, 172.5, true, null], ["Jane", "female", 22, 167.2, false, null]]
注意, 這些 JSON 資料都是以字串形式做交換, json 模組提供了 loads() 與 dumps() 函式可用來在 JSON 字串與 Python 字典之間做轉換.
1. 檢視 json 模組內容 :
匯入 json 模組後可以用 dir() 函式檢視其內容 :
>>> import json
>>> dir(json)
['JSONDecodeError', 'JSONDecoder', 'JSONEncoder', '__all__', '__author__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '__version__', '_default_decoder', '_default_encoder', 'codecs', 'decoder', 'detect_encoding', 'dump', 'dumps', 'encoder', 'load', 'loads', 'scanner']
也可以用下列自訂模組 members 之 list_members() 函式來進一步了解那些是類別與函式 :
# members.py
import inspect
def varname(x):
return [k for k,v in inspect.currentframe().f_back.f_locals.items() if v is x][0]
def list_members(parent_obj):
members=dir(parent_obj)
parent_obj_name=varname(parent_obj)
for mbr in members:
child_obj=eval(parent_obj_name + '.' + mbr)
if not mbr.startswith('_'):
print(mbr, type(child_obj))
將此函式存成 members.py 模組, 放在目前供作目錄下, 然後匯入其 list_members() 函式來檢視 json 模組 :
>>> from members import list_members
>>> list_members(json)
JSONDecodeError <class 'type'>
JSONDecoder <class 'type'>
JSONEncoder <class 'type'>
codecs <class 'module'>
decoder <class 'module'>
detect_encoding <class 'function'>
dump <class 'function'>
dumps <class 'function'>
encoder <class 'module'>
load <class 'function'>
loads <class 'function'>
scanner <class 'module'>
常用的函式如下表 :
json 常用函式 | 說明 |
load(file) | 從檔案參考 file 讀取 JSON 資料為 Python 字典後傳回 |
loads(str) | 從 JSON 字串 str 讀取 JSON 資料為 Python 字典後傳回 |
dump(data, file) | 將 Python 字典寫入 .json 檔案參考 file |
dumps(data [, sort_keys, indent]) | 將 Python 字典轉成 JSON 字串後傳回 |
這四個函式會在 JSON 字串與 Python 字典之間進行轉換, 注意有無 s 的差別在於, 有 s 的處理對象是 JSON 字串; 而無 s 的則是 ,json 檔案.
Javascript 與 Python 資料類型之對照如下表 :
JSON 資料類型 | Python 資料類型 |
物件 object | 字典 dict |
陣列 array | 串列 list |
字串 string | 字串 str |
整數 int | 整數 int |
浮點數 Number | 浮點數 float |
布林值 true | 布林值 True |
布林值 false | 布林值 False |
空值 null | 空值 None |
注意, Javascript 的 true/false 對應於 Python 的 True/False, 而 Javascript 的 null 則對應於 Python 的 None.
2. 呼叫 json.loads() 將 JSON 字串轉成 Python 字典/串列 :
json.loads(str) 用來將 JSON 字串轉成 Python 字典, 傳入值為一個 JSON 字串, 傳回值為一個 Python 字典或串列, 例如 :
>>> json_str='{"name": "Tony", "gender": "male", "age": 26, "height": 172.5, "married": true, "religion": null}'
>>> obj=json.loads(json_str)
>>> type(obj)
<class 'dict'>
>>> obj
{'name': 'Tony', 'gender': 'male', 'age': 26, 'height': 172.5, 'married': True, 'religion': None}
可見 json.loads() 將 JSON 字串載入後轉成 Python 字典, 其值也轉成對應之 Python 資料型態.
其次來看多個物件放在陣列的情況, 如上所述, JSON 資料中只能有一個 Javascript 物件, 若有多個物件要放在陣列中成為物件陣列 :
>>> json_str='[{"name": "Tony", "gender": "male", "age": 26, "height": 172.5, "married": true, "religion": null}, {"name": "Jane", "gender": "female", "age": 22, "height": 167.2, "married": false, "religion": null}]' # JSON 資料為兩個物件組成之陣列
>>> obj=json.loads(json_str)
>>> type(obj)
<class 'list'>
>>> obj
[{'name': 'Tony', 'gender': 'male', 'age': 26, 'height': 172.5, 'married': True, 'religion': None}, {'name': 'Jane', 'gender': 'female', 'age': 22, 'height': 167.2, 'married': False, 'religion': None}]
可見 loads() 會將 JSON 字串轉成字典串列.
3. 呼叫 json.dumps() 將 Python 字典/串列轉成 JSON 字串 :
dumps() 是 loads() 的反函式, 它可將 Python 字典/串列轉成 JSON 字串, 例如 :
>>> data={'name': 'Tony', 'gender': 'male', 'age': 26, 'height': 172.5, 'married': True, 'religion': None}
>>> json_str=json.dumps(data)
>>> type(json_str)
<class 'str'>
>>> json_str
'{"name": "Tony", "gender": "male", "age": 26, "height": 172.5, "married": true, "religion": null}'
下面是將字典串列轉成 JSON 字串的測試 :
>>> data=[{'name': 'Tony', 'gender': 'male', 'age': 26, 'height': 172.5, 'married': True, 'religion': None}, {'name': 'Jane', 'gender': 'female', 'age': 22, 'height': 167.2, 'married': False, 'religion': None}]
>>> json_str=json.dumps(data)
>>> json_str
'[{"name": "Tony", "gender": "male", "age": 26, "height": 172.5, "married": true, "religion": null}, {"name": "Jane", "gender": "female", "age": 22, "height": 167.2, "married": false, "religion": null}]'
當物件多的時候會很難閱讀, 可用 indent 參數來調整縮排, 例如 :
>>> json_str=json.dumps(data, indent=4)
>>> json_str
'[\n {\n "name": "Tony",\n "gender": "male",\n "age": 26,\n "height": 172.5,\n "married": true,\n "religion": null\n },\n {\n "name": "Jane",\n "gender": "female",\n "age": 22,\n "height": 167.2,\n "married": false,\n "religion": null\n }\n]'
要用 print() 輸出才看得到效果 :
>>> print(json_str)
[
{
"name": "Tony",
"gender": "male",
"age": 26,
"height": 172.5,
"married": true,
"religion": null
},
{
"name": "Jane",
"gender": "female",
"age": 22,
"height": 167.2,
"married": false,
"religion": null
}
]
4. 呼叫 json.dump() 將 Python 字典/串列寫入 .json 檔案 :
呼叫 json.dump() 並傳入 Python 字典/串列與檔案參考可將其寫入 json 檔案 (ANSI 編碼) :
>>> data={'name': 'Tony', 'gender': 'male', 'age': 26, 'height': 172.5, 'married': True, 'religion': None}
>>> with open('test.json', 'w') as f:
json.dump(data, f)
開啟目前工作目錄下的 test.json 內容如下, 編碼格式為 ANSI :
{"name": "Tony", "gender": "male", "age": 26, "height": 172.5, "married": true, "religion": null}
可見 dump() 已經將 true/false 轉成 True/False, None 轉成 null 了, 同時也把原先字典使用的單引號全部轉成雙引號, 因為 JSON 格式中字串必須使用雙引號.
如果字典中所有非英文字母會轉成 unicode, 例如將 name 欄位值改成 "金秀賢" :
{"name": "\u91d1\u79c0\u8ce2", "gender": "male", "age": 26, "height": 172.5, "married": true, "religion": null}
5. 呼叫 json.load() 載入 .json 檔案轉成 Python 字典/串列 :
呼叫 json.load(file) 可以從檔案 file 讀取 JSON 資料, 它會傳回一個字/串列, 例如上面範例的檔案 test.json :
{"name": "\u91d1\u79c0\u8ce2", "gender": "male", "age": 26, "height": 172.5, "married": true, "religion": null}
>>> with open('test.json', 'r') as f:
data=json.load(f)
>>> data
{'name': '金秀賢', 'gender': 'male', 'age': 26, 'height': 172.5, 'married': True, 'religion': None}
沒有留言:
張貼留言