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 = { ‘User-agent‘
用 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 文件的方法。
-
Class 15 - 1 數據存儲——文件存儲