CSV ,全稱為 Comma-Separated Values ,中文可以叫逗號分隔值或字符分隔值,其文件以純文本形式存儲表格數據。該文件是一個字符序列,可以由任意數目的記錄組成,記錄間以某種換行符分隔。每條記錄由欄位組成,欄位間的分隔符是其他字符或字符串,最常見的是逗號或制表符。不過所有記錄都有完全相同的欄位序列,相當於一個結構化表的純文本形式。它比 Excel 文件更加簡潔, XLS 文本是電子表格,它包含了文本、數值、公式和格式等內容,而 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
我們可以發現每條記錄中間都空了一行,這可不太好啊!那麼如何解決這個問題呢?首先從 open 方法入手,我們先查看一下 open 方法,打開命令提示符輸入 python 或 ipython 回車進交互式解釋器環境。然後直接輸入 help(open) 回車,如圖所示。
首先看這個函數的原型, 1 個必選參數, 7 個默認參數,我們注意到其中一個默認參數是 newline ,引起上面的結果出現空行可能就是因為它了,我們往下滑,找到對 newline 參數的解釋,如圖所示。
稍微翻譯一下, newline 控制全局的換行如何工作(它僅僅應用於文本模式)。它可以是None,『』,『\n』,『\r』 和 『\r\n』。它按照如下方式工作:
在輸入時,如果 newline 是 None ,全局的換行模式是可用的,輸入中的行可以以 『\n』,『\r』 或者 『\r\n』 結尾,並且在被返回給調用者之前,這些會被解釋成 『\n』 。如果它是空字符串,全局換行模式也是可用的,但是每一行的結束符都會原封不動的返回給調用者。如果它有其他任何合法的值,輸入的行僅僅按照被傳入的字符串來終止,並且行的結束符被原封不動的返回給調用者。
在輸出時,如果 newline 是 None ,任何被寫入的 『\n』 字符會被解釋成系統默認的行分隔符, os.linesep 。如果 newline 是 『』 或者 『\n』 ,就沒有解釋發生。如果 newline 是任何其他合法的值,任何被寫入的 『\n』 字符被解釋給傳入的字符串。
簡直是雲裡霧裡啊~!這裡看不懂沒有關係,我們去看一下 csv 的官方文檔(https://docs.python.org/3/library/csv.html#id3),找到如圖所示的位置。
上面是 csv 模塊的 writer 的函數原型,稍微翻譯一下下面一段:
返回一個編寫器對象,負責將用戶的數據轉換為給定類似文件的對象上的分隔字符串。 csvfile 可以是任何擁有寫方法的對象。如果 csvfile 是一個文件對象,它應該伴隨著 newline 參數為空字符串的過程被打開。……為什麼呢?點擊上面的 [1] 跳到最下面的注釋部分,如圖所示。
如果 newline=『』 沒有被規定,嵌入在引號欄位中的換行符將無法正確解釋,並且在使用 \r\n 行尾的平臺上將添加額外的 \r 。由於 csv 模塊遵循它自己的換行處理標準,規定 newline=『』 總歸是安全的。
按照官方文檔所說的內容,我們修改上面的例子。
import csv
with open('data.csv', 'w', newline='')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])
再次運行一下,然後去看看文件內容,其內容如下:
id,name,age
10001,Mike,20
10002,Bob,22
10003,Jordan,21終於成功了!可以看到,寫入的文本默認以逗號分隔,調用一次 writerow() 方法即可寫入一行數據。用 Excel 打開的結果如圖所示。
如果想修改列與列之間的分隔符,可以傳入 delimiter 參數,其代碼如下:
import csv
with open('data.csv', 'w', newline='')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', newline='')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', newline='')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})
這裡先定義 3 個欄位,用 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', newline='')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', newline='')as csvfile:
fieldnames = ['id', 'name', 'age']
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
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)
運行結果如下:
['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)
運行結果如下:
我們可以發現中文沒有對齊,感覺有點怪怪的~!我們首先需要知道為什麼沒有對齊。它之所以沒有對齊,是因為它以最長的字符串為標準進行右對齊的,同時又因為漢字是寬字符(佔用兩個字符的位置),它現在還是以為中文漢字只有佔一個字符位。如何解決這個問題呢?其實很簡單,設置屬性 display.unicode.ambiguous_as_wide 和 display.unicode.east_asian_width ,將這兩個屬性都設置為 True 即可,代碼如下:
import pandas as pd
pd.set_option('display.unicode.ambiguous_as_wide', True)
pd.set_option('display.unicode.east_asian_width', True)
df = pd.read_csv('data.csv')
print(df)
運行結果如下:
在做數據分析的時候,此種方法用的比較多,也是一種比較方便地讀取 CSV 文件的方法。
我們了解了 CSV 文件的寫入和讀取方式。這也是一種常用的數據存儲方式,需要熟練掌握。
今天的文章有不懂的可以加群,群號:822163725,備註:小陳學Python,不備註可是會被拒絕的哦~!
最後歡迎大家掃碼關注