
文章目录
📖 开篇导读
在之前的课程中,我们学习了字符串、文件操作、正则表达式等,能够处理基本的文本数据。但在现实开发中,数据往往以结构化格式进行交换和存储,最常见的三种格式是:JSON、CSV 和 XML。
- JSON(JavaScript Object Notation):轻量级数据交换格式,广泛用于 Web API、配置文件、NoSQL 数据库。易读、易解析,是前后端通信的事实标准。
- CSV(Comma-Separated Values):表格数据的纯文本表示,Excel、数据库导入导出、数据分析中无处不在。
- XML(eXtensible Markup Language):标记语言,常用于配置文件(如 Java 项目)、SOAP 协议、Office 文档等。
Python 内置了强大的模块来处理这三种格式:json、csv、xml.etree.ElementTree。掌握它们,你就可以轻松地从 API 获取数据、导出报表、解析复杂文档。
💡 工作场景:
- 后端开发:接收前端 JSON 请求,返回 JSON 响应;读取配置文件(JSON/YAML);导出 CSV 报表。
- 数据分析:读取 CSV 数据集,处理后保存为 JSON。
- 爬虫:解析 XML 格式的网站地图、RSS 订阅。
- 自动化:将 Excel 转换为 CSV,批量处理配置文件。
本课将系统学习:
- JSON 的序列化(
dump/dumps)与反序列化(load/loads),处理自定义对象。 - CSV 的读取(
reader/DictReader)与写入(writer/DictWriter),处理不同方言。 - XML 的解析与生成(
ElementTree),XPath 基本使用。 - 实战:API 数据抓取、CSV 报表生成、XML 配置文件读写。
学完本课,你将能够自如地在这些数据格式之间转换,应对工作中的各种数据需求。
🎯 学习目标
| 目标编号 | 具体掌握内容 | 对应面试/工作价值 |
|---|---|---|
| 1️⃣ | 掌握 JSON 的编码(dumps)和解码(loads),以及文件读写 | Web API 交互基础 |
| 2️⃣ | 处理 JSON 中的自定义对象(default 和 object_hook) | 序列化复杂数据 |
| 3️⃣ | 读写 CSV 文件,使用 csv.reader/writer 以及字典形式 | 数据导出导入 |
| 4️⃣ | 处理 CSV 方言(delimiter、quotechar)和特殊字符 | 兼容各种格式 |
| 5️⃣ | 解析和生成 XML,使用 ElementTree 遍历/查找/修改元素 | 配置文件、旧系统集成 |
| 6️⃣ | 掌握 XPath 基本表达式(find/findall)定位 XML 元素 | 高效提取数据 |
🔥 面试考点:“
json.loads和json.dumps的区别?”“如何将自定义对象序列化为 JSON?”“CSV 读写时如何处理引号和逗号?”“XML 解析的几种方式?”
📚 知识点理论精讲
一、JSON 数据格式
JSON 是 JavaScript 对象表示法的子集,但已被几乎所有语言支持。它基于键值对和有序列表。
1.1 JSON 支持的数据类型
| JSON 类型 | Python 类型 |
|---|---|
对象 {} | 字典 dict |
数组 [] | 列表 list |
字符串 "..." | 字符串 str |
数字 123 / 12.3 | 整数 int / 浮点 float |
布尔值 true/false | True/False |
空 null | None |
1.2 json 模块核心函数
json.dumps(obj, indent=None, ensure_ascii=True, ...):将 Python 对象序列化为 JSON 字符串。json.loads(json_str):将 JSON 字符串反序列化为 Python 对象。json.dump(obj, file, ...):将 Python 对象序列化并写入文件。json.load(file):从文件中读取 JSON 并反序列化。
1.3 常用参数
indent:缩进空格数,美化输出。ensure_ascii:默认为True,将非 ASCII 字符转义为\uXXXX;设为False可输出中文。sort_keys:按键排序输出。
1.4 自定义对象序列化
通过 default 参数指定一个函数,用于将自定义类型转换为可序列化的字典。
def custom_encoder(obj):
if isinstance(obj, Person):
return {"name": obj.name, "age": obj.age}
raise TypeError
json_str = json.dumps(person, default=custom_encoder)
反序列化时使用 object_hook 将字典转换为对象。
二、CSV 数据格式
CSV 是逗号分隔值,每行代表一条记录,字段间用分隔符(通常是逗号)隔开。也可以使用其他分隔符(如制表符、分号)。
2.1 csv 模块核心读写
csv.reader(file, dialect='excel', **fmtparams):返回一个读取器,每行返回列表。csv.writer(file, dialect='excel', **fmtparams):返回写入器,支持writerow和writerows。csv.DictReader(file):将第一行作为列名,每行返回字典。csv.DictWriter(file, fieldnames):写入字典数据。
2.2 常用参数
delimiter:分隔符,默认为,。quotechar:引用字符,默认为"。quoting:引用方式(csv.QUOTE_MINIMAL、csv.QUOTE_ALL等)。lineterminator:行终止符,默认为\r\n。
2.3 处理含逗号字段
自动用双引号包裹包含分隔符或换行符的字段。
三、XML 数据格式
XML 是可扩展标记语言,使用标签定义元素,可嵌套,自描述。
3.1 XML 结构示例
<people>
<person id="1">
<name>张三</name>
<age>25</age>
</person>
</people>
3.2 xml.etree.ElementTree 模块
ElementTree.parse(file):从文件解析 XML 得到树对象。ElementTree.fromstring(xml_str):从字符串解析。getroot():获取根元素。- 元素方法:
tag、attrib、text,find()、findall()、iter()。
3.3 查找元素
find(tag):返回第一个匹配的子元素。findall(tag):返回所有匹配的子元素列表。iter(tag):递归遍历所有匹配的元素(可省略 tag 遍历所有)。
支持 XPath 简单表达式,如 ".//name" 表示所有后代中的 name 元素。
3.4 创建与修改 XML
root = ET.Element("root")
child = ET.SubElement(root, "child")
child.text = "value"
tree = ET.ElementTree(root)
tree.write("output.xml", encoding="utf-8", xml_declaration=True)
💻 代码案例实操
案例1:JSON 基础——字典与文件互转
"""
json_basic.py
演示 JSON 的基础序列化与反序列化
"""
import json
# Python 对象
data = {
"name": "张三",
"age": 25,
"hobbies": ["reading", "coding"],
"is_student": False,
"address": None
}
# 序列化为 JSON 字符串
json_str = json.dumps(data, indent=4, ensure_ascii=False)
print("JSON 字符串:")
print(json_str)
# 反序列化为 Python 对象
obj = json.loads(json_str)
print("反序列化后:", obj)
print(type(obj)) # dict
# 写入文件
with open("data.json", "w", encoding="utf-8") as f:
json.dump(data, f, indent=4, ensure_ascii=False)
# 从文件读取
with open("data.json", "r", encoding="utf-8") as f:
loaded = json.load(f)
print("从文件加载:", loaded)
案例2:自定义对象 JSON 序列化
"""
custom_json_encoder.py
使用 default 和 object_hook 处理自定义对象
"""
import json
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def person_encoder(obj):
"""自定义编码器:将 Person 转为字典"""
if isinstance(obj, Person):
return {"__type__": "Person", "name": obj.name, "age": obj.age}
raise TypeError
def person_decoder(dct):
"""自定义解码器:将字典转为 Person"""
if dct.get("__type__") == "Person":
return Person(dct["name"], dct["age"])
return dct
# 序列化
p = Person("李四", 30)
json_str = json.dumps(p, default=person_encoder, indent=2)
print("序列化结果:", json_str)
# 反序列化
p2 = json.loads(json_str, object_hook=person_decoder)
print("反序列化后:", p2.name, p2.age)
案例3:JSON 与 API 交互——获取天气信息
"""
api_json.py
模拟从 API 获取 JSON 数据并解析(使用 requests 库)
"""
import json
import requests
# 示例:调用免费天气 API(实际需替换真实 URL)
def fetch_weather(city):
# 这里使用一个模拟的 JSON 响应代替真实请求
mock_response = {
"city": city,
"temperature": 22.5,
"unit": "C",
"condition": "Sunny",
"forecast": [
{"day": "Monday", "temp": 23},
{"day": "Tuesday", "temp": 21}
]
}
# 实际开发中: response = requests.get(f"https://api.weather.com?city={city}")
# return response.json()
return mock_response
# 获取并解析
weather = fetch_weather("Beijing")
print(f"城市: {weather['city']}, 温度: {weather['temperature']}{weather['unit']}")
# 保存到文件
with open("weather.json", "w") as f:
json.dump(weather, f, indent=2)
案例4:CSV 读写基础
"""
csv_basic.py
读写 CSV 文件,包括列表和字典形式
"""
import csv
# 写入 CSV (列表形式)
data = [
["姓名", "年龄", "城市"],
["张三", 25, "北京"],
["李四", 30, "上海"],
["王五", 28, "广州"]
]
with open("people.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerows(data)
# 读取 CSV (列表形式)
with open("people.csv", "r", encoding="utf-8") as f:
reader = csv.reader(f)
for row in reader:
print(row)
# 写入 CSV (字典形式,带表头)
people = [
{"name": "赵六", "age": 35, "city": "深圳"},
{"name": "周七", "age": 32, "city": "成都"}
]
with open("people_dict.csv", "w", newline="", encoding="utf-8") as f:
fieldnames = ["name", "age", "city"]
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(people)
# 读取字典形式 CSV
with open("people_dict.csv", "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
print(f"{row['name']} - {row['age']}岁 - {row['city']}")
案例5:处理 CSV 特殊字符和自定义分隔符
"""
csv_special.py
处理含逗号、换行符的字段,以及使用分号分隔符
"""
import csv
# 包含逗号的数据
data = [
["姓名", "描述"],
["张三", "爱好:阅读,编程"], # 描述中包含逗号
["李四", "多行\n描述"] # 包含换行符
]
# 写入时自动引用特殊字符
with open("special.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f, quoting=csv.QUOTE_MINIMAL) # 默认行为
writer.writerows(data)
# 用分号作为分隔符写入
semicolon_data = [["a", "b"], ["c", "d"]]
with open("semicolon.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f, delimiter=';')
writer.writerows(semicolon_data)
# 读取分号分隔的文件
with open("semicolon.csv", "r", encoding="utf-8") as f:
reader = csv.reader(f, delimiter=';')
for row in reader:
print(row)
案例6:XML 解析与遍历
"""
xml_parse.py
使用 ElementTree 解析 XML 文件
"""
import xml.etree.ElementTree as ET
# 示例 XML 字符串
xml_str = """
<bookstore>
<book category="fiction">
<title lang="en">Python编程</title>
<author>张三</author>
<price>59.90</price>
</book>
<book category="tech">
<title lang="zh">深度学习入门</title>
<author>李四</author>
<price>89.00</price>
</book>
</bookstore>
"""
# 从字符串解析
root = ET.fromstring(xml_str)
# 遍历所有 book 元素
for book in root.findall("book"):
title = book.find("title").text
author = book.find("author").text
price = book.find("price").text
category = book.get("category")
print(f"《{title}》作者:{author}, 价格:{price}, 分类:{category}")
# 使用 XPath 查找所有标题(任意层级)
titles = root.findall(".//title")
for title in titles:
print("标题:", title.text, "语言:", title.get("lang"))
案例7:修改和创建 XML 文件
"""
xml_create_modify.py
生成 XML 并写入文件,修改已有 XML
"""
import xml.etree.ElementTree as ET
# 创建 XML 树
root = ET.Element("students")
for i, name in enumerate(["张三", "李四", "王五"], 1):
student = ET.SubElement(root, "student", id=str(i))
name_elem = ET.SubElement(student, "name")
name_elem.text = name
score = ET.SubElement(student, "score")
score.text = str(85 + i * 2)
tree = ET.ElementTree(root)
tree.write("students.xml", encoding="utf-8", xml_declaration=True)
print("已生成 students.xml")
# 修改已有的 XML
tree = ET.parse("students.xml")
root = tree.getroot()
# 将所有人的分数加5分
for score_elem in root.findall(".//score"):
new_score = int(score_elem.text) + 5
score_elem.text = str(new_score)
# 添加新学生
new_student = ET.SubElement(root, "student", id="4")
name_elem = ET.SubElement(new_student, "name")
name_elem.text = "赵六"
score_elem = ET.SubElement(new_student, "score")
score_elem.text = "95"
tree.write("students_modified.xml", encoding="utf-8", xml_declaration=True)
print("已保存修改后的文件")
案例8:XML 与 JSON 互转
"""
xml_json_convert.py
将 XML 转换为 JSON 格式(简单映射)
"""
import json
import xml.etree.ElementTree as ET
def xml_to_dict(element):
"""递归将 XML 元素转为字典/列表结构"""
result = {}
# 处理属性
if element.attrib:
result["@attributes"] = element.attrib
# 处理子元素
children = list(element)
if children:
child_dict = {}
for child in children:
child_data = xml_to_dict(child)
if child.tag in child_dict:
# 多个同名子元素合并为列表
if not isinstance(child_dict[child.tag], list):
child_dict[child.tag] = [child_dict[child.tag]]
child_dict[child.tag].append(child_data)
else:
child_dict[child.tag] = child_data
result.update(child_dict)
else:
# 无子元素,存放文本内容
result["#text"] = element.text.strip() if element.text else ""
return result if result else element.text
# 示例
xml_str = "<person id='1'><name>张三</name><age>25</age></person>"
root = ET.fromstring(xml_str)
data = xml_to_dict(root)
json_str = json.dumps(data, indent=2, ensure_ascii=False)
print("转换后的 JSON:\n", json_str)
案例9:CSV 转 JSON(数据清洗)
"""
csv_to_json.py
将 CSV 文件转换为 JSON 格式
"""
import csv
import json
def csv_to_json(csv_file, json_file):
data = []
with open(csv_file, "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
# 可选:转换数据类型
if "age" in row:
row["age"] = int(row["age"])
data.append(row)
with open(json_file, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
# 创建测试 CSV
with open("sample.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["name", "age", "city"])
writer.writerow(["张三", "25", "北京"])
writer.writerow(["李四", "30", "上海"])
csv_to_json("sample.csv", "output.json")
print("转换完成,查看 output.json")
案例10:处理大型 XML(迭代解析)
"""
xml_iterparse.py
使用 iterparse 逐元素解析大型 XML,避免内存爆炸
"""
import xml.etree.ElementTree as ET
# 模拟生成一个大 XML 文件(实际中可能是大日志)
def create_large_xml():
root = ET.Element("root")
for i in range(1000):
child = ET.SubElement(root, "item", id=str(i))
child.text = f"内容{i}"
tree = ET.ElementTree(root)
tree.write("large.xml", encoding="utf-8")
create_large_xml()
# 使用 iterparse 流式处理
def process_large_xml(file):
for event, elem in ET.iterparse(file, events=("end",)):
if elem.tag == "item":
print(f"处理: {elem.get('id')} - {elem.text}")
# 处理完后清除元素,释放内存
elem.clear()
# 清除根元素
for event, elem in ET.iterparse(file, events=("start",)):
if elem.tag == "root":
elem.clear()
process_large_xml("large.xml")
⚠️ 易错点避坑总结
| 序号 | 坑点描述 | 后果 | 解决方案 |
|---|---|---|---|
| 1 | JSON 中键名必须用双引号 | 单引号 JSON 字符串无法解析 | 使用 json.loads,不要手动拼接 |
| 2 | json.dump 写入文件时忘记指定 encoding='utf-8' | 中文可能乱码 | 显式指定编码 |
| 3 | CSV 读取时未指定 newline='' | 可能产生空行 | 在 open() 中添加 newline='' |
| 4 | 包含逗号字段未使用引用 | CSV 列错位 | 写入时使用 csv.QUOTE_MINIMAL(默认自动)或 QUOTE_ALL |
| 5 | csv.DictWriter 未先 writeheader | 缺少列名行 | 显式调用 writeheader() |
| 6 | XML 命名空间处理 | XPath 查找失败 | 使用 {namespace}tag 或注册命名空间 |
| 7 | XML 解析时未处理多级命名空间 | 找不到元素 | 使用 root.findall('.//{http://example.com}tag') |
| 8 | iterparse 没有适时 clear() 导致内存增长 | 大文件内存耗尽 | 处理完每个元素后调用 elem.clear() |
| 9 | XML 属性与子元素同名冲突 | 转换字典时覆盖 | 区分存取(如加 @ 前缀) |
| 10 | CSV 方言不一致(如 Excel 导出使用分号) | 读取失败 | 使用 delimiter=';' 参数 |
📝 课后实战练习题
第1题:JSON 配置文件读写
创建一个 config.json,包含 host、port、debug 字段。编写程序读取并修改 port 值,然后保存回文件。
第2题:CSV 成绩统计
有一个 scores.csv,列名为 name, math, english, chinese。读取 CSV,计算每个学生的总分和平均分,将结果输出到 report.csv,增加 total 和 average 列。
第3题:XML 解析 RSS 订阅源
使用 xml.etree.ElementTree 解析一个 RSS 订阅源(如 http://feeds.bbci.co.uk/news/rss.xml),提取每个 <item> 的标题、链接、发布时间,打印出来。
第4题:JSON 转换为 CSV
从 https://jsonplaceholder.typicode.com/users 获取用户 JSON 数据,将其关键字段(id, name, email, phone)导出到 users.csv。
第5题:XML 生成配置文件
根据给定的字典数据,生成 XML 配置文件,如:
config = {
"server": {"host": "localhost", "port": 8080},
"logging": {"level": "INFO", "file": "app.log"}
}
生成对应的 XML 表示。
第6题:CSV 处理大文件分块
编写程序,使用 csv.reader 分块读取一个大 CSV 文件(每块1000行),对每块进行统计(如某列总和),最后输出总量。展示内存高效处理。
第7题:JSON 和 XML 互转(完整转换器)
实现一个 xml_to_json 函数,将任意 XML 字符串转换为 JSON,支持属性、文本、嵌套元素,列表处理。再实现反向 json_to_xml 转换。
🧠 知识点思维导图总结
🔜 下节课预告
掌握了常见数据格式的读写后,我们需要将这些数据存储到关系型数据库中。下一节课我们将学习 SQLite/MySQL 数据库基础,以及如何使用 Python 操作数据库。
第38课:数据库基础:MySQL安装配置与SQL语句零基础入门
内容包括:
- 关系数据库和 SQL 基础(DDL/DML/DQL)
- MySQL 安装与基本配置(或使用 SQLite 免安装)
- Python 连接数据库(
mysql-connector-python或sqlite3) - 执行 SQL 语句、事务处理
- 实战:创建表、增删改查
数据库是后端开发的必备技能,掌握它你将能构建数据驱动的应用。
🌟 学习鼓励:JSON、CSV、XML 是日常开发中频繁打交道的数据格式。通过本课的学习,你已经具备处理外部数据的能力。请动手完成练习,特别是 JSON 与 CSV 互转、XML 解析等任务,这些是实际项目中的高频操作。下一阶段我们将进入数据库编程,继续保持热情!
🔗《50节课 Python 从入门到精通》系列课程导航
🌟 感谢您耐心阅读到这里!
💡 如果本文对您有所启发欢迎:
👍 点赞📌 收藏 📤 分享给更多需要的伙伴。
🗣️ 期待在评论区看到您的想法, 共同进步。
🔔 关注我,持续获取更多干货内容~
🤗 我们下篇文章见~

380

被折叠的 条评论
为什么被折叠?



