Python資料處理(一):處理 JSON、XML、CSV 三種格式資料

solocoder發表於2019-01-27

Python 資料處理系列部落格來啦!

本系列將以《Python資料處理》這本書為基礎,以書中每章一篇部落格的形式帶大家一起學習 Python 資料處理。書中有些地方講的不太詳細,我會查閱其他資料來補充,力爭每篇部落格都把知識點涵蓋全且通俗易懂。

這本書主要講了如何用 Python 處理各種型別的檔案,如 JSON、XML、CSV、Excel、PDF 等。後面幾章還會講資料清洗、網頁抓取、自動化和規模化等使用技能。我也是 Python 初學者,將以初學者的角度寫文章,所以部落格對初學者比較友好。

python 基礎如果你還不熟練,可以先看看我的另一篇部落格:十分鐘快速入門 Python

100 多位經驗豐富的開發者參與,在 Github 上獲得了近 1000star 的全棧全平臺開源專案想了解或參與嗎?
專案地址:github.com/cachecats/c…

前言

以易於機器理解的方式來儲存資料的檔案格式,通常被稱作機器可讀的 (machine readable)。常見的機器可讀格式包括:

  • 逗號分隔值(Comma-Separated Values,CSV)
  • JavaScript 物件符號(JavaScript Object Notation,JSON)
  • 可擴充套件標記語言(eXtensible Markup Language,XML)

在口語和書面語中,提到這些資料格式時通常使用它們的短名字(如 CSV)。 我們將使用這些縮寫 。

一、CSV資料

CSV 檔案(簡稱為 CSV)是指將資料列用逗號分隔的檔案。檔案的副檔名是 .csv。

另一種資料型別,叫作製表符分隔值(tab-separated values,TSV)資料,有時也與 CSV歸為一類。TSV 與 CSV 唯一的不同之處在於,資料列之間的分隔符是製表符(tab),而不是逗號。檔案的副檔名通常是 .tsv,但有時也用 .csv 作為副檔名。從本質上來看,.tsv 檔案與 .csv 檔案在Python 中的作用是相同的。

我們採用的資料來源是從世界衛生組織(www.who.int/zh/home)中下載…

開啟世衛組織官網後,點選“健康主題”,“資料和統計” 就能找到很多資料。

Python資料處理(一):處理 JSON、XML、CSV 三種格式資料

這裡下載了關於嬰幼兒護理的統計資料,並重新命名為 data.csv

csv 檔案可以直接用 Excel 開啟直觀的看到,我們用 Excel 開啟如下圖:

Python資料處理(一):處理 JSON、XML、CSV 三種格式資料

接下來就要用 Python 來簡單的處理這些資料。

以列表的形式讀取csv資料

編寫一個讀取 csv 檔案的程式:

import csv

csvfile = open('./data.csv', 'r')
reader = csv.reader(csvfile)

for row in reader:
    print(row)
複製程式碼

import csv 將匯入 Python 自帶的 csv 模組。csvfile = open('./data.csv', 'r') 以只讀的形式開啟資料檔案並儲存到變數 csvfile 中。然後呼叫 csv 的 reader() 方法將輸出儲存在 reader 變數中,再用 for 迴圈將資料輸出。

執行程式,控制檯輸出:

Python資料處理(一):處理 JSON、XML、CSV 三種格式資料

可以看到跟 Excel 開啟的內容一致。

以字典的形式讀取csv資料

改一下程式碼,以字典的形式讀取 csv

import csv

csvfile = open('./data.csv', 'r')
reader = csv.DictReader(csvfile)

for row in reader:
    print(row)
複製程式碼

控制檯輸出:

Python資料處理(一):處理 JSON、XML、CSV 三種格式資料

二、JSON資料

同樣在世衛組織官網下載資料來源,重新命名為 data.json。用格式化工具開啟 json 檔案如下:

Python資料處理(一):處理 JSON、XML、CSV 三種格式資料

編寫程式對 json 進行解析

import json

# 將 json 檔案讀取成字串
json_data = open('./data.json').read()
# 對json資料解碼
data = json.loads(json_data)
# data 的型別是 字典dict
print(type(data))
# 直接列印 data
print(data)
# 遍歷字典
for k, v in data.items():
    print(k + ':' + str(v))
複製程式碼

控制檯輸出:

Python資料處理(一):處理 JSON、XML、CSV 三種格式資料

Python3 中可以使用 json 模組來對 JSON 資料進行編解碼,它包含了兩個函式:

  • json.dumps(): 對資料進行編碼。
  • json.loads(): 對資料進行解碼。

在json的編解碼過程中,python 的原始型別與json型別會相互轉換,具體的轉化對照如下:

Python 編碼為 JSON 型別轉換對應表:

Python JSON
dict object
list, tuple array
str string
int, float, int- & float-derived Enums number
True true
False false
None null

JSON 解碼為 Python 型別轉換對應表:

JSON Python
object dict
array list
string str
number (int) int
number (real) float
true True
false False
null None

三、XML 資料

XML 格式的資料既便於機器讀取,也便於人工讀取。但是對於本章的資料集來說,預覽並理解 CSV 檔案和 JSON 檔案要比 XML 檔案容易得多。

xml 格式說明:

  • Tag: 使用<和>包圍的部分;
  • Element:被Tag包圍的部分,如 2003,可以認為是一個節點,它可以有子節點;
  • Attribute:在Tag中可能存在的 name/value 對,如示例中的 title="Enemy Behind",一般表示屬性。

世衛組織的資料不好理解,我們們用個簡單的能看得懂的電影資料來做演示:

<?xml version="1.0" encoding="UTF-8"?>
<collection shelf="New Arrivals">
    <movie title="Enemy Behind">
        <type>War, Thriller</type>
        <format>DVD</format>
        <year>2003</year>
        <rating>PG</rating>
        <stars>10</stars>
        <description>Talk about a US-Japan war</description>
    </movie>
    <movie title="Transformers">
        <type>Anime, Science Fiction</type>
        <format>DVD</format>
        <year>1989</year>
        <rating>R</rating>
        <stars>8</stars>
        <description>A schientific fiction</description>
    </movie>
    <movie title="Trigun">
        <type>Anime, Action</type>
        <format>DVD</format>
        <episodes>4</episodes>
        <rating>PG</rating>
        <stars>10</stars>
        <description>Vash the Stampede!</description>
    </movie>
    <movie title="Ishtar">
        <type>Comedy</type>
        <format>VHS</format>
        <rating>PG</rating>
        <stars>2</stars>
        <description>Viewable boredom</description>
    </movie>
</collection>
複製程式碼

這個資料相對來說比較簡單,只有三層。但原理掌握了,幾層資料都能搞定。

下面編寫程式碼對上面的 xml 進行解析,解析之後再分別格式化成字典和 json 格式的資料輸出:

from xml.etree import ElementTree as ET
import json

tree = ET.parse('./resource/movie.xml')
root = tree.getroot()

all_data = []

for movie in root:
    # 儲存電影資料的字典
    movie_data = {}
    # 儲存屬性的字典
    attr_data = {}

    # 取出 type 標籤的值
    movie_type = movie.find('type')
    attr_data['type'] = movie_type.text

    # 取出 format 標籤的值
    movie_format = movie.find('format')
    attr_data['format'] = movie_format.text

    # 取出 year 標籤的值
    movie_year = movie.find('year')
    if movie_year:
        attr_data['year'] = movie_year.text

    # 取出 rating 標籤的值
    movie_rating = movie.find('rating')
    attr_data['rating'] = movie_rating.text

    # 取出 stars 標籤的值
    movie_stars = movie.find('stars')
    attr_data['stars'] = movie_stars.text

    # 取出 description 標籤的值
    movie_description = movie.find('description')
    attr_data['description'] = movie_description.text

    # 獲取電影名字,以電影名為字典的鍵,屬性資訊為字典的值
    movie_title = movie.attrib.get('title')
    movie_data[movie_title] = attr_data
    # 存入列表中
    all_data.append(movie_data)

print(all_data)
# all_data 此時是一個列表物件,用 json.dumps() 將python物件轉換為 json 字串
json_str = json.dumps(all_data)
print(json_str)
複製程式碼

註釋寫的比較詳細,下面介紹下 ElementTree 提供的方法。

3.1 解析的三種方法

ElementTree 解析 xml 有三種方法:

  1. 呼叫parse()方法,返回解析樹

    tree = ET.parse('./resource/movie.xml')
    root = tree.getroot()
    複製程式碼
  2. 呼叫from_string(),返回解析樹的根元素

    data = open('./resource/movie.xml').read()
    root = ET.fromstring(data)
    複製程式碼
  3. 呼叫 ElementTree 類的 ElementTree(self, element=None, file=None) 方法

    tree = ET.ElementTree(file="./resource/movie.xml")
    root = tree.getroot() 
    複製程式碼

3.2 Element 物件

class xml.etree.ElementTree.Element(tag, attrib={}, **extra)

Element 物件的屬性

  • tag: 標籤
  • text: 去除標籤,獲得標籤中的內容。
  • attrib: 獲取標籤中的屬性和屬性值。
  • tail: 這個屬性可以用來儲存與元素相關聯的附加資料。它的值通常是字串,但可能是特定於應用程式的物件。

Element 物件的方法

  1. clear():清除所有子元素和所有屬性,並將文字和尾部屬性設定為None。

  2. get(attribute_name, default=None):通過指定屬性名獲取屬性值。

  3. items():以鍵值對的形式返回元素屬性。

  4. keys():以列表的方式返回元素名。

  5. set(attribute_name,attribute_value):在某標籤中設定屬性和屬性值。

  6. append(subelement):將元素子元素新增到元素的子元素內部列表的末尾。

  7. extend(subelements):追加子元素。

  8. find(match, namespaces=None):找到第一個匹配的子元素,match可以是標籤名或者path。返回Elememt例項或None。

  9. findall(match, namespaces=None):找到所有匹配的子元素,返回的是一個元素列表。

  10. findtext(match, default=None, namespaces=None):找到匹配第一個子元素的文字。返回的是匹配元素中的文字內容。

  11. getchildren():Python3.2後使用 list(elem) 或 iteration.

  12. getiterator(tag=None):Python3.2後使用 Element.iter()

  13. iter(tag=None):以當前元素為根建立樹迭代器。迭代器遍歷這個元素和它下面的所有元素(深度優先順序)。如果標籤不是None或’*’,那麼只有標籤等於標籤的元素才會從迭代器返回。如果在迭代過程中修改樹結構,則結果是未定義的。

  14. iterfind(match, namespaces=None): 匹配滿足條件的子元素,返回元素。

3.3 ElementTree 物件

class xml.etree.ElementTree.ElementTree(element=None, file=None)

ElementTree是一個包裝器類,這個類表示一個完整的元素層次結構,併為標準XML的序列化新增了一些額外的支援。

  1. setroot(element):替換根元素,原來的根元素中的內容會消失。

  2. find(match, namespaces=None):從根元素開始匹配和 Element.find()作用一樣。

  3. findall(match, namespaces=None):從根元素開始匹配和 Element.findall()作用一樣。

  4. findtext(match, default=None, namespaces=None):從根元素開始匹配和 Element.findtext()作用一樣。

  5. getiterator(tag=None):Python3.2後使用 ElementTree.iter() 代替。

  6. iter(tag=None):迭代所有元素

  7. iterfind(match, namespaces=None):從根元素開始匹配和 Element.iterfind()作用一樣。

  8. parse(source, parser=None):解析xml文字,返回根元素。

  9. write(file, encoding=”us-ascii”, xml_declaration=None, default_namespace=None, method=”xml”, *, short_empty_elements=True):寫出XML文字。

對 JSON、XML、CSV三種格式資料的處理就講完啦,下期講如何處理 Excel 檔案,歡迎關注。


全棧全平臺開源專案 CodeRiver

CodeRiver 是一個免費的專案協作平臺,願景是打通 IT 產業上下游,無論你是產品經理、設計師、程式設計師或是測試,還是其他行業人員,只要有好的創意、想法,都可以來 CodeRiver 免費釋出專案,召集志同道合的隊友一起將夢想變為現實!

CodeRiver 本身還是一個大型開源專案,致力於打造全棧全平臺企業級精品開源專案。涵蓋了 React、Vue、Angular、小程式、ReactNative、Android、Flutter、Java、Node 等幾乎所有主流技術棧,主打程式碼質量。

目前已經有近 100 名優秀開發者參與,github 上的 star 數量將近 1000 個。每個技術棧都有多位經驗豐富的大佬坐鎮,更有兩位架構師指導專案架構。無論你想學什麼語言處於什麼技術水平,相信都能在這裡學有所獲。

通過 高質量原始碼 + 部落格 + 視訊,幫助每一位開發者快速成長。

專案地址:github.com/cachecats/c…


您的鼓勵是我們前行最大的動力,歡迎點贊,歡迎送小星星✨ ~

Python資料處理(一):處理 JSON、XML、CSV 三種格式資料

相關文章