Python数据处理(一):处理 JSON、XML、CSV 三种格式数据

2022-04-06 13:28:29 浏览数 (1)

Python 数据处理系列博客来啦!

本系列将以《Python数据处理》这本书为基础,以书中每章一篇博客的形式带大家一起学习 Python 数据处理。书中有些地方讲的不太详细,我会查阅其他资料来补充,力争每篇博客都把知识点涵盖全且通俗易懂。

这本书主要讲了如何用 Python 处理各种类型的文件,如 JSON、XML、CSV、Excel、PDF 等。后面几章还会讲数据清洗、网页抓取、自动化和规模化等使用技能。我也是 Python 初学者,将以初学者的角度写文章,所以博客对初学者比较友好。

python 基础如果你还不熟练,可以先看看我的另一篇博客:十分钟快速入门 Python

100 多位经验丰富的开发者参与,在 Github 上获得了近 1000star 的全栈全平台开源项目想了解或参与吗? 项目地址:https://github.com/cachecats/coderiver

前言

以易于机器理解的方式来存储数据的文件格式,通常被称作机器可读的 (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 中的作用是相同的。

我们采用的数据源是从世界卫生组织(https://www.who.int/zh/home)中下载的数据。

打开世卫组织官网后,点击“健康主题”,“数据和统计” 就能找到很多数据。

这里下载了关于婴幼儿护理的统计数据,并重命名为 data.csv

csv 文件可以直接用 Excel 打开直观的看到,我们用 Excel 打开如下图:

接下来就要用 Python 来简单的处理这些数据。

以列表的形式读取csv数据

编写一个读取 csv 文件的程序:

代码语言:javascript复制
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 循环将数据输出。

运行程序,控制台输出:

可以看到跟 Excel 打开的内容一致。

以字典的形式读取csv数据

改一下代码,以字典的形式读取 csv

代码语言:javascript复制
import csv

csvfile = open('./data.csv', 'r')
reader = csv.DictReader(csvfile)
for row in reader:
    print(row)

控制台输出:

二、JSON数据

同样在世卫组织官网下载数据源,重命名为 data.json。用格式化工具打开 json 文件如下:

编写程序对 json 进行解析

代码语言:javascript复制
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))

控制台输出:

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",一般表示属性。

世卫组织的数据不好理解,咱们用个简单的能看得懂的电影数据来做演示:

代码语言:javascript复制
<?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 格式的数据输出:

代码语言:javascript复制
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 = {}
<span class="hljs-comment"># 取出 type 标签的值</span>
movie_type = movie.find(<span class="hljs-string">'type'</span>)
attr_data[<span class="hljs-string">'type'</span>] = movie_type.text

<span class="hljs-comment"># 取出 format 标签的值</span>
movie_format = movie.find(<span class="hljs-string">'format'</span>)
attr_data[<span class="hljs-string">'format'</span>] = movie_format.text

<span class="hljs-comment"># 取出 year 标签的值</span>
movie_year = movie.find(<span class="hljs-string">'year'</span>)
<span class="hljs-keyword">if</span> movie_year:
    attr_data[<span class="hljs-string">'year'</span>] = movie_year.text

<span class="hljs-comment"># 取出 rating 标签的值</span>
movie_rating = movie.find(<span class="hljs-string">'rating'</span>)
attr_data[<span class="hljs-string">'rating'</span>] = movie_rating.text

<span class="hljs-comment"># 取出 stars 标签的值</span>
movie_stars = movie.find(<span class="hljs-string">'stars'</span>)
attr_data[<span class="hljs-string">'stars'</span>] = movie_stars.text

<span class="hljs-comment"># 取出 description 标签的值</span>
movie_description = movie.find(<span class="hljs-string">'description'</span>)
attr_data[<span class="hljs-string">'description'</span>] = movie_description.text

<span class="hljs-comment"># 获取电影名字,以电影名为字典的键,属性信息为字典的值</span>
movie_title = movie.attrib.get(<span class="hljs-string">'title'</span>)
movie_data[movie_title] = attr_data
<span class="hljs-comment"># 存入列表中</span>
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 有三种方法:

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 文件。

项目地址:https://github.com/cachecats/coderiver

0 人点赞