【Python3網路爬蟲開發實戰】5-資料儲存-1 檔案儲存-2 JSON檔案儲存

崔慶才丨靜覓發表於2018-03-21

JSON,全稱為JavaScript Object Notation, 也就是JavaScript物件標記,它通過物件和陣列的組合來表示資料,構造簡潔但是結構化程度非常高,是一種輕量級的資料交換格式。本節中,我們就來了解如何利用Python儲存資料到JSON檔案。

1. 物件和陣列

在JavaScript語言中,一切都是物件。因此,任何支援的型別都可以通過JSON來表示,例如字串、數字、物件、陣列等,但是物件和陣列是比較特殊且常用的兩種型別,下面簡要介紹一下它們。

  • 物件:它在JavaScript中是使用花括號{}包裹起來的內容,資料結構為{key1:value1, key2:value2, ...}的鍵值對結構。在物件導向的語言中,key為物件的屬性,value為對應的值。鍵名可以使用整數和字串來表示。值的型別可以是任意型別。
  • 陣列:陣列在JavaScript中是方括號[]包裹起來的內容,資料結構為["java", "javascript", "vb", ...]的索引結構。在JavaScript中,陣列是一種比較特殊的資料型別,它也可以像物件那樣使用鍵值對,但還是索引用得多。同樣,值的型別可以是任意型別。

所以,一個JSON物件可以寫為如下形式:

[{
    "name": "Bob",
    "gender": "male",
    "birthday": "1992-10-18"
}, {
     "name": "Selina",
    "gender": "female",
    "birthday": "1995-10-18"
}]
複製程式碼

由中括號包圍的就相當於列表型別,列表中的每個元素可以是任意型別,這個示例中它是字典型別,由大括號包圍。

JSON可以由以上兩種形式自由組合而成,可以無限次巢狀,結構清晰,是資料交換的極佳方式。

2. 讀取JSON

Python為我們提供了簡單易用的庫來實現JSON檔案的讀寫操作,我們可以呼叫庫的loads()方法將JSON文字字串轉為JSON物件,可以通過dumps()方法將JSON物件轉為文字字串。

例如,這裡有一段JSON形式的字串,它是str型別,我們用Python將其轉換為可操作的資料結構,如列表或字典:

import 

str = '''
[{
    "name": "Bob",
    "gender": "male",
    "birthday": "1992-10-18"
}, {
    "name": "Selina",
    "gender": "female",
    "birthday": "1995-10-18"
}]
'''
print(type(str))
data = .loads(str)
print(data)
print(type(data))
複製程式碼

執行結果如下:

<class 'str'>
[{'name': 'Bob', 'gender': 'male', 'birthday': '1992-10-18'}, {'name': 'Selina', 'gender': 'female', 'birthday': '1995-10-18'}]
<class 'list'>
複製程式碼

這裡使用loads()方法將字串轉為JSON物件。由於最外層是中括號,所以最終的型別是列表型別。

這樣一來,我們就可以用索引來獲取對應的內容了。例如,如果想取第一個元素裡的name屬性,就可以使用如下方式:

data[0]['name']
data[0].get('name')
複製程式碼

得到的結果都是:

Bob
複製程式碼

通過中括號加0索引,可以得到第一個字典元素,然後再呼叫其鍵名即可得到相應的鍵值。獲取鍵值時有兩種方式,一種是中括號加鍵名,另一種是通過get()方法傳入鍵名。這裡推薦使用get()方法,這樣如果鍵名不存在,則不會報錯,會返回None。另外,get()方法還可以傳入第二個引數(即預設值),示例如下:

data[0].get('age')
data[0].get('age', 25)
複製程式碼

執行結果如下:

None
25
複製程式碼

這裡我們嘗試獲取年齡age,其實在原字典中該鍵名不存在,此時預設會返回None。如果傳入第二個引數(即預設值),那麼在不存在的情況下返回該預設值。

值得注意的是,JSON的資料需要用雙引號來包圍,不能使用單引號。例如,若使用如下形式表示,則會出現錯誤:

import 

str = '''
[{
    'name': 'Bob',
    'gender': 'male',
    'birthday': '1992-10-18'
}]
'''
data = .loads(str)
複製程式碼

執行結果如下:

.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 3 column 5 (char 8)
複製程式碼

這裡會出現JSON解析錯誤的提示。這是因為這裡資料用單括號來包圍,請千萬注意JSON字串的表示需要用雙引號,否則loads()方法會解析失敗。

如果從JSON文字中讀取內容,例如這裡有一個data.文字檔案,其內容是剛才定義的JSON字串,我們可以先將文字檔案內容讀出,然後再利用loads()方法轉化:

import 

with open('data.', 'r') as file:
    str = file.read()
    data = .loads(str)
    print(data)
複製程式碼

執行結果如下:

[{'name': 'Bob', 'gender': 'male', 'birthday': '1992-10-18'}, {'name': 'Selina', 'gender': 'female', 'birthday': '1995-10-18'}]
複製程式碼

3. 輸出JSON

另外,我們還可以呼叫dumps()方法將JSON物件轉化為字串。例如,將上例中的列表重新寫入文字:

import 

data = [{
    'name': 'Bob',
    'gender': 'male',
    'birthday': '1992-10-18'
}]
with open('data.', 'w') as file:
    file.write(.dumps(data))
複製程式碼

利用dumps()方法,我們可以將JSON物件轉為字串,然後再呼叫檔案的write()方法寫入文字,結果如圖5-2所示。

【Python3網路爬蟲開發實戰】5-資料儲存-1 檔案儲存-2 JSON檔案儲存

圖5-2 寫入結果

另外,如果想儲存JSON的格式,可以再加一個引數indent,代表縮排字元個數。示例如下:

with open('data.', 'w') as file:
    file.write(.dumps(data, indent=2))
複製程式碼

此時寫入結果如圖5-3所示。

【Python3網路爬蟲開發實戰】5-資料儲存-1 檔案儲存-2 JSON檔案儲存

圖5-3 寫入結果

這樣得到的內容會自動帶縮排,格式會更加清晰。

另外,如果JSON中包含中文字元,會怎麼樣呢?例如,我們將之前的JSON的部分值改為中文,再用之前的方法寫入到文字:

import 

data = [{
    'name': '王偉',
    'gender': '男',
    'birthday': '1992-10-18'
}]
with open('data.', 'w') as file:
    file.write(.dumps(data, indent=2))
複製程式碼

寫入結果如圖5-4所示。

【Python3網路爬蟲開發實戰】5-資料儲存-1 檔案儲存-2 JSON檔案儲存

圖5-4 寫入結果

可以看到,中文字元都變成了Unicode字元,這並不是我們想要的結果。

為了輸出中文,還需要指定引數ensure_asciiFalse,另外還要規定檔案輸出的編碼:

with open('data.', 'w', encoding='utf-8') as file:
    file.write(.dumps(data, indent=2, ensure_ascii=False))
複製程式碼

寫入結果如圖5-5所示。

【Python3網路爬蟲開發實戰】5-資料儲存-1 檔案儲存-2 JSON檔案儲存

圖5-5 寫入結果

可以發現,這樣就可以輸出JSON為中文了。

本節中,我們瞭解了用Python進行JSON檔案讀寫的方法,後面做資料解析時經常會用到,建議熟練掌握。

本資源首發於崔慶才的個人部落格靜覓: Python3網路爬蟲開發實戰教程 | 靜覓

如想了解更多爬蟲資訊,請關注我的個人微信公眾號:進擊的Coder

weixin.qq.com/r/5zsjOyvEZ… (二維碼自動識別)


相關文章