上一篇文章: Python3網絡爬蟲實戰---30、解析庫的使用:PyQuery
下一篇文章: Python3網絡爬蟲實戰---3二、數據存儲:關係型數據庫存儲:MySQL
咱們用解析器解析出數據以後,接下來的一步就是對數據進行存儲了,保存的形式能夠多種多樣,最簡單的形式能夠直接保存爲文本文件,如 TXT、Json、CSV 等等,另外還能夠保存到數據庫中,如關係型數據庫 MySQL,非關係型數據庫 MongoDB、Redis 等等。那麼本章咱們就來統一瞭解一下數據的保存方式。javascript
文件存儲形式能夠是多種多樣的,好比能夠保存成 TXT 純文本形式,也能夠保存爲 Json 格式、CSV 格式等,本節咱們來了解下文本文件的存儲方式。html
將數據保存到 TXT 文本的操做很是簡單,並且 TXT 文本幾乎兼容任何平臺,可是有個缺點就是不利於檢索,因此若是對檢索和數據結構要求不高,追求方便第一的話,能夠採用 TXT 文本存儲,本節咱們來看下利用 Python 保存 TXT 文本文件的方法。java
本節咱們要保存知乎發現頁面的熱門問題部分,將其問題和答案統一保存成文本形式。數據庫
首先能夠用 Requests 將網頁源代碼獲取下來,而後使用 PyQuery 解析庫進行解析,接下來將提取的標題、回答者、回答保存到文本,代碼以下:json
import requests from pyquery import PyQuery as pq url = 'https://www.zhihu.com/explore' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36' } html = requests.get(url, headers=headers).text doc = pq(html) items = doc('.explore-tab .feed-item').items() for item in items: question = item.find('h2').text() author = item.find('.author-link-line').text() answer = pq(item.find('.content').html()).text() file = open('explore.txt', 'a', encoding='utf-8') file.write('\n'.join([question, author, answer])) file.write('\n' + '=' * 50 + '\n') file.close()
在這裏主要是爲了演示文件保存的方式,所以 Requests 異常處理部分在此省去,咱們首先用 Requests 提取了知乎發現頁面,而後將熱門問題的問題、回答者、答案全文提取出來,而後利用了Python提供的 open() 方法打開一個文本文件,獲取一個文件操做對象,這裏賦值爲 file,而後利用 file 對象的 write() 方法將提取的內容寫入文件,最後記得調用一下 close() 方法將其關閉,這樣抓取的內容便可成功寫入到文本中了。
運行程序,能夠發如今本地生成了一個 explore.txt 文件.
這樣熱門問答的內容就被保存文文本形式了。
在這裏 open() 方法的第一個參數即爲要保存的目標文件名稱,第二個參數爲 a,表明以追加方式寫入到文本,另外咱們還指定了文件的編碼爲utf-8,最後寫入完成以後,咱們還須要調用 close() 方法來關閉文件對象。segmentfault
在剛纔的實例中,第二個參數咱們設置成了 a,這樣在每次寫入文本時不會清空源文件,而是在文件末尾寫入新的內容,這是一種文件打開方式。關於文件打開方式,其實還有另外的幾種,在此列舉以下:數組
另外文件寫入還有一種簡寫方法,那就是使用 with as 語法,在 with 控制塊結束時,文件會自動關閉,因此就不須要再調用 close() 方法了。
因此上面的保存方式咱們能夠簡寫以下:網絡
with open('explore.txt', 'a', encoding='utf-8') as file: file.write('\n'.join([question, author, answer])) file.write('\n' + '=' * 50 + '\n')
若是想保存時將原文清空,那麼能夠將第二個參數改寫爲 w,代碼以下:數據結構
with open('explore.txt', 'w', encoding='utf-8') as file: file.write('\n'.join([question, author, answer])) file.write('\n' + '=' * 50 + '\n')
以上即是利用 Python 將結果保存爲 TXT 文件的方法,此種方法簡單易用,操做高效,是一種最基本的保存數據的方法。函數
Json,全稱爲 JavaScript Object Notation, 也就是 JavaScript 對象標記,經過對象和數組的組合來表示數據,構造簡潔可是結構化程度很是高,它是一種輕量級的數據交換格式,本節咱們來了解一下利用 Python 保存數據到 Json 文件的方法。
在 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 能夠由以上兩種形式自由組合而成,能夠無限次嵌套,結構清晰,是數據交換的極佳方式。
Python 爲咱們提供了簡單易用的 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'>
在這裏咱們使用了 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' }] ''' data = json.loads(str)
運行結果:
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 3 column 5 (char 8)
在這裏會出現 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)
運行結果:
[{'name': 'Bob', 'gender': 'male', 'birthday': '1992-10-18'}, {'name': 'Selina', 'gender': 'female', 'birthday': '1995-10-18'}]
以上是讀取 Json 文件的方法。
另外咱們還能夠調用 dumps() 方法來將 Json 對象轉化爲字符串。
例如咱們將剛上例中的列表從新寫入到文本。
import json data = [{ 'name': 'Bob', 'gender': 'male', 'birthday': '1992-10-18' }] with open('data.json', 'w') as file: file.write(json.dumps(data))
利用 dumps() 方法咱們能夠將 Json 對象轉爲字符串,而後再調用文件的 write() 方法便可寫入到文本,結果如圖 5-2 所示:
圖 5-2 寫入結果
另外若是咱們想保存 Json 的格式,能夠再加一個參數 indent,表明縮進字符個數。
with open('data.json', 'w') as file: file.write(json.dumps(data, indent=2))
寫入結果如圖 5-3 所示:
圖 5-3 寫入結果
這樣獲得的內容會自動帶有縮進,格式會更加清晰。
另外若是 Json 中包含中文字符,例如咱們將以前的 Json 的部分值改成中文,再用以前的方法寫入到文本。
import json data = [{ 'name': '王偉', 'gender': '男', 'birthday': '1992-10-18' }] with open('data.json', 'w') as file: file.write(json.dumps(data, indent=2))
寫入結果如圖 5-4 所示:
圖 5-4 寫入結果
能夠看到中文字符都變成了 Unicode 字符,這並非咱們想要的結果。
爲了輸出中文,咱們還須要指定一個參數 ensure_ascii 爲 False,另外規定文件輸出的編碼。
with open('data.json', 'w', encoding='utf-8') as file: file.write(json.dumps(data, indent=2, ensure_ascii=False))
寫入結果如圖 5-5 所示:
圖 5-5 寫入結果
這樣咱們就能夠輸出 Json 爲中文了,因此若是字典中帶有中文的內容咱們須要設置 ensure_ascii 參數爲 False 纔可正常寫入中文。
本節咱們瞭解了用 Python 進行 Json 文件讀寫的方法,在後面作數據解析時常常會用到,建議熟練掌握。
CSV,全稱叫作 Comma-Separated Values,中文能夠叫作逗號分隔值或字符分隔值,其文件以純文本形式存儲表格數據。該文件是一個字符序列,能夠由任意數目的記錄組成,記錄間以某種換行符分隔,每條記錄由字段組成,字段間的分隔符是其它字符或字符串,最多見的是逗號或製表符,不過全部記錄都有徹底相同的字段序列,至關於一個結構化表的純文本形式,它相比 Excel 文件更加簡介,XLS 文本是電子表格,它包含了文本、數值、公式和格式等內容,而 CSV 中不包含這些內容,就是特定字符分隔的純文本,結構簡單清晰,因此有時候咱們用 CSV 來保存數據是比較方便的,本節咱們來說解下 Python 讀取和寫入 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() 方法傳入每行的數據便可完成寫入。
運行結束後會生成一個名爲 data.csv 的文件,數據就成功寫入了,直接文本形式打開的話內容以下:
id,name,age 10001,Mike,20 10002,Bob,22 10003,Jordan,21
能夠看到寫入的文本默認是以逗號分隔的,調用一次 writerow() 方法便可寫入一行數據,咱們用 Excel 打開的結果如圖 5-6 所示:
圖 5-6 打開結果
若是咱們想修改列與列之間的分隔符能夠傳入 delimiter 參數,代碼以下:
import csv with open('data.csv', 'w') as csvfile: writer = csv.writer(csvfile, delimiter=' ') writer.writerow(['id', 'name', 'age']) writer.writerow(['10001', 'Mike', 20]) writer.writerow(['10002', 'Bob', 22]) writer.writerow(['10003', 'Jordan', 21])
例如這裏在初始化寫入對象的時候傳入 delimiter 爲空格,這樣輸出的結果的每一列就是以空格分隔的了,內容以下:
id name age 10001 Mike 20 10002 Bob 22 10003 Jordan 21
另外咱們也能夠調用 writerows() 方法同時寫入多行,此時參數就須要爲二維列表,例如:
import csv with open('data.csv', 'w') as csvfile: writer = csv.writer(csvfile) writer.writerow(['id', 'name', 'age']) writer.writerows([['10001', 'Mike', 20], ['10002', 'Bob', 22], ['10003', 'Jordan', 21]])
輸出效果是相同的,內容以下:
id,name,age 10001,Mike,20 10002,Bob,22 10003,Jordan,21
可是通常狀況下爬蟲爬取的都是結構化數據,咱們通常會用字典來表示,在 csv 庫中也提供了字典的寫入方式,實例以下:
import csv with open('data.csv', 'w') as csvfile: fieldnames = ['id', 'name', 'age'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) 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})
在這裏咱們先定義了三個字段,用 fieldnames 表示,而後傳給 DictWriter 初始化一個字典寫入對象,而後能夠先調用 writeheader() 方法先寫入頭信息,而後再調用 writerow() 方法傳入相應字典便可,最終寫入的結果是徹底相同的,內容以下:
id,name,age 10001,Mike,20 10002,Bob,22 10003,Jordan,21
這樣咱們就能夠完成字典到 CSV 文件的寫入了。
另外若是咱們想追加寫入的話能夠修改文件的打開模式,如將 open() 函數的第二個參數改爲 a 就能夠變成追加寫入,代碼以下:
import csv with open('data.csv', 'a') as csvfile: fieldnames = ['id', 'name', 'age'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writerow({'id': '10004', 'name': 'Durant', 'age': 22})
這樣在上面的基礎上再執行這段代碼,文件內容便會變成:
id,name,age 10001,Mike,20 10002,Bob,22 10003,Jordan,21 10004,Durant,22
可見數據被追加寫入到了文件中。
若是咱們要寫入中文內容的話可能會遇到字符編碼的問題,此時咱們須要給 open() 參數指定一個編碼格式,好比這裏再寫入一行包含中文的數據,代碼須要改寫以下:
import csv with open('data.csv', 'a', encoding='utf-8') as csvfile: fieldnames = ['id', 'name', 'age'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writerow({'id': '10005', 'name': '王偉', 'age': 22})
在這裏須要給 open() 函數指定編碼,不然可能會發生編碼錯誤。
以上即是 CSV 文件的寫入方法。
另外若是咱們接觸過 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)
運行結果:
['id', 'name', 'age'] ['10001', 'Mike', '20'] ['10002', 'Bob', '22'] ['10003', 'Jordan', '21'] ['10004', 'Durant', '22'] ['10005', '王偉', '22']
在這裏咱們構造的是 Reader 對象,經過遍歷輸出了每行的內容,每一行都是一個列表形式,注意在這裏若是 CSV 文件中包含中文的話須要指定文件編碼。
另外若是咱們接觸過 Pandas 的話,能夠利用 read_csv() 方法將數據從 CSV 中讀取出來,例如:
import pandas as pd df = pd.read_csv('data.csv') print(df)
運行結果:
id name age 0 10001 Mike 20 1 10002 Bob 22 2 10003 Jordan 21 3 10004 Durant 22 4 10005 王偉 22
在作數據分析的時候此種方法用的比較多,也是一種比較方便的讀取 CSV 文件的方法。
本節咱們瞭解了 CSV 文件的寫入和讀取方式,它也是一種經常使用的數據存儲方式,須要熟練掌握。
上一篇文章: Python3網絡爬蟲實戰---30、解析庫的使用:PyQuery
下一篇文章: Python3網絡爬蟲實戰---3二、數據存儲:關係型數據庫存儲:MySQL