Class 15 - 1 資料儲存——檔案儲存
儲存的形式可以多種多樣,最簡單的形式是 接儲存為文字檔案,如 TXT、JSON、CSV等。還可以儲存到資料庫中,如關係型資料庫 MySQL ,非關係型資料庫 MongoDB、Redis等。
一、TXT文字儲存
- 基本例項:
-
可以用 requests 將網頁原始碼獲取下來,然後使用 pyquery 解析庫解析,接下來將提取的標題、 回答者、 回答儲存到文字,程式碼:
import requests from pyquery import PyQuery as pq url = 'https://www.zhihu.com/explore' headers
用 requests 提取知乎的"發現"頁面,然後將熱門話題的問題、回答者、答案全文提取出來,然後利用 Python 提供的open()方法開啟一個文字檔案,獲取一個檔案操作物件,這裡賦值為 file,接著利用 file 對 象的 write()方法將提取的內容寫入檔案,最後呼叫 ιlose()方法將其關閉,這
-
- 開啟方式
-
open()方法的第二個引數設定成了 a,這樣在每次寫入文字時不會清空原始檔, 而是在檔案末尾寫入新的內容,這是一種檔案開啟方式。
-
r:以只讀方式開啟檔案。 檔案的指標將會放在檔案的開頭。 這是預設模式。
- rb:以二進位制只讀方式開啟一個檔案。 檔案指標將會放在檔案的開頭。
- r+:以讀寫方式開啟一個檔案, 檔案指標將會放在檔案的開頭。
- rb+:以二進位制讀寫方式開啟一個檔案。 檔案指標將會放在檔案的開頭。
- w:以寫入方式開啟一個檔案。 如果該檔案已存在,則將其覆蓋。 如果該檔案不存在,則建立新檔案。
- wb:以二進位制寫入方式開啟一個檔案。 如果該檔案已存在,則將其覆蓋。 如果該檔案不存 在, 則建立新檔案
- w+:以讀寫方式開啟一個檔案。 如果該檔案已存在,則將其覆蓋。 如果該檔案不存在,則創 建新檔案
- wb+:以二進位制讀寫格式開啟一個檔案。 如果該檔案已存在, 則將其覆蓋。 如果該檔案不存 在, 則建立新檔案。
- a: 以追加方式開啟一個檔案。 如果該檔案已存在,檔案指標將會放在檔案結尾, 如果該檔案不存在, 則建立新檔案來寫入。
- ab:以二進位制追加方式開啟一個檔案。 如果該檔案已存在,則檔案指標將會放在檔案結尾,如果該檔案不存在,則建立新檔案來寫入
- a+:以讀寫方式開啟一個檔案。 如果該檔案已存在,檔案指標將會放在檔案的結尾。 檔案打 開時會是追加模式。 如果檔案不存在,則建立新檔案來讀寫。
- ab+:以二進位制追加方式開啟一個檔案。 如果該檔案已存在,則檔案指標將會放在檔案結尾。 如果該檔案不存在,則建立新檔案用於讀寫
-
-
- 簡化寫法
- 使用 with as 語法。在 with 控制塊結束時,檔案會自動關閉,不需要再呼叫 close()方法。示例:
with open('explore.txt', 'a', encoding='utf-8') as file: file.write('\n'.jason([question,author,answers])) file.write('\n'+'='*50+'\n')
如果想儲存時將原文清空,那麼可以將第二個引數改寫為 w,示例:
with open('explore.txt', 'w', encoding='utf-8') as file: file.write('\n'.jason([question,author,answers])) file.write('\n'+'='*50+'\n')
- 使用 with as 語法。在 with 控制塊結束時,檔案會自動關閉,不需要再呼叫 close()方法。示例:
二、Json檔案儲存
JSON,全稱為 JavaScript Object Notation, 是 JavaScript物件標記, 通過物件和陣列的組合來表示資料,構造簡潔但結構化程度非常高,是一種輕量級的資料交換格式。
- 物件和陣列
-
在 JavaScript語言中,一切都是物件。 因此,任何支援的型別都可以通過 JSON來表示,如:字串、數字、物件、陣列等,物件和陣列是比較特殊且常用的兩種型別
- 物件:在 JavaScript 中是使用花括號{}包裹起來的內容,資料結構為{key1: value1, key2: value2,… }的鍵值對結構。 在面向物件的語言中, key 為物件的屬性, value 為對應的值。 鍵名可以使用整數和字串來表示。 值的型別可以是任意型別。
- 陣列:陣列在 JavaScript 中是方括號[]包裹起來的內容,資料結構為["java","javascript","vb",.... ]的索引結構。在JavaScript 中, 陣列是一種比較特殊的資料型別,也可以像物件那樣使用鍵值對,但還是索引用得多。 同樣,值的型別可以是任意型別。
- 所以,一個JSON物件可以寫成如下形式:
[{ "name": "Bob", "gender": "male", "birthday": "1992-10-18",}, {"name": "Snlina", "gender": "female", "birthday": "1995-10-18" }]
由中括號包圍的就相當於列表型別,列表中的每個元素可以是任意型別,這個示例中它是字典型別,由大括號包圍。
JSON 可以由以上兩種形式自由組合而成,可以無限次巢狀,結構清晰,是資料交換的極佳方式。
- 所以,一個JSON物件可以寫成如下形式:
-
- 讀取JSON
-
可以呼叫 JSON 庫 的 loads()方法將 JSON 文字字串轉為 JSON物件,可以通過 dumps()方法將 JSON 物件轉為文字字串。
例:一段 JSON 形式的字串,是 str 型別,可以用 Python 將其轉換為可操作的資料結構——列表或字典:import json str = ''' [{ "name":"Bob", "gender":"male", "birthday": "1992-10-18" },{ "name": "Selina", "gender":"female", "birthday": "1995-10-18" }] ''' print(type(str)) data = json.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'>
View Code使用 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 json str = ''' [{ 'name':'Bob', 'gender':'male', 'birthday': '1992-10-18' },{ 'name': 'Selina', 'gender':'female', 'birthday':'1995-10-18' }] ''' data = json.loads(str) 輸出: json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 2 column 8 (char 8)
View Code出現 JSON解析錯誤提示。注意:JSON 字串的表示需要用雙引號,否則 loads()方法會解析失敗。
-
從 JSON 文字中讀取內容,例:有一個 data.json 檔案,內容是剛才定義的 JSON 字串,可以先將文字檔案內容讀出,然後再利用 loads()方法轉化:
import json with open('data.json','r') as file: str = file.read() data = json.loads(str) print(data)
-
-
輸出JSON
-
可以呼叫 dumps()方法將 JSON 物件轉化為字串。 例:將例中的列表重新寫入文字:
import json data = ''' [{ "name": "Bob", "gender": "male", "birthday": "1992-10-18" }] ''' with open('data.json','a',encoding='utf-8') as f: f.write(json.dumps(data))
利用 dumps()方法,可以將 JSON 物件轉為字串,然後再呼叫檔案的 write()方法寫入文字
-
如果想儲存 JSON 的格式,可以再加一個引數 indent,代表縮排字元個數。 示例:
with open('data.json','a',encoding='utf-8') as f: f.write(json.dumps(data,indent=2))
這樣得到的內容會自動帶縮排,格式更加清晰。
-
如果 JSON 中包含中文字元,需要指定引數 ensure_ascii 為 False,還要規定檔案輸出的編碼:
with open('data.json','w',encoding='utf-8') as f: f.write(json.dumps(data,indent=2,ensure_ascii= False))
-
三、CSV檔案儲存
- 寫入
-
import csv with open('data.csv','w') as csvfile: writer =csv.writer(csvfile) writer.writerow(['id','name','age']) writer.writerow(['10001','Mike',20]) writer.writerow(['10002','Bob',22]) writer.writerow(['10003','Jordan',21])
首先開啟 data.csv 檔案,然後指定開啟的模式為 w(寫入),獲得檔案控制代碼,隨後呼叫 csv 庫 的 writer()方法初始化寫人物件,傳入該控制代碼,然後呼叫 writerow()方法傳入每行的資料即可完成寫入。
寫人的文字預設以逗號分隔,呼叫一次 writerow()方法即可寫入一行資料。 -
如果想修改列與列之間的分隔符,可以傳入 delimiter 引數,程式碼如下:
import csv with open('data.csv','w') as csvfile: writer =csv.writer(csvfile,delimiter='') --snip--
裡在初始化寫入物件時傳入 delimiter 為空格, 此時輸出結果的每一列就是以空格分隔。
-
也可以呼叫 writerows()方法同時寫入多行, 此時引數需要為二維列表,例:
import csv with open('data.csv','w') as csvfile: writer =csv.writer(csvfile) writer.writerow(['id','name','age']) writer.writerow(['10001','Mike',20],['10002','Bob',22],['10003','Jordan',21])
輸出內容相同。
-
是一般情況下,爬蟲爬取的都是結構化資料,一般會用字典來表示。在 CSV 庫中也提供了字典的寫入方式,示例:
import csv with open('data.csv','w') as csvfile: filenames = ['id','name','age'] writer = csv.DictWriter(csvfile,fieldnames=filenames) writer.writeheader() writer.writerow({'id':'10001','name':'Mike','age':20}) writer.writerow({'id':'10002','name':'Bob','age':22}) writer.writerow({'id':'10003','name':'Jordan','age':21})
先定義 3 個欄位,用 fieldnames 表示,再將其傳給 DictWriter 來初始化一個字典寫人對 象,接著呼叫 writeheader()方法先寫人頭資訊,然後再呼叫 writerow()方法傳人相應字典。
-
如果想追加寫人,可以修改檔案的開啟模式,即將 open()函式的第二個引數改成 a,示例:
import csv with open('data.csv','a') as csvfile: filenames = ['id','name','age'] writer = csv.DictWriter(csvfile,fieldnames=filenames) writer.writerow({'id':'10004','name':'Durant','age':22})
-
如果要寫入中文內容,可能會遇到字元編碼的問題,此時需要給 open()引數指定編碼格式。 例如,再寫入一行包含中文的資料,程式碼需要改寫:
import csv with open('data.csv','a',encoding='utf-8') as csvfile: filenames = ['id','name','age'] writer = csv.DictWriter(csvfile,fieldnames=filenames) writer.writerow({'id':'10005','name':'王偉','age':22})
這裡需要給 open()函式指定編碼,否則可能發生編碼錯誤。
-
如果接觸過 pandas 庫的話,可以呼叫 DataFrame 物件的 to_csv()方法來將資料寫人 csv 檔案中。
-
-
讀取
-
同樣可以使用 csv 庫來讀取 csv 檔案。 如,將寫入的檔案內容讀取出來,如下:
import csv with open('data.csv','r',encoding='utf-8') as csvfile: reader =csv.reader(csvfile) for row in reader: print(row)
這裡構造的是 Reader 物件,通過遍歷輸出了每行的內容,每一行都是一個列表形式。 注意, 如果 csv 檔案中包含中文的話,還需要指定檔案編碼。
-
如果知道 pandas庫,可以利用 read_csv()方法將資料從 csv 中讀取出來,如:
import pandas as pd df=pd.read_csv('data.csv') print(df)
在做資料分析的時候,此種方法用得比較多,也是一種比較方便地讀取 csv 檔案的方法。
-