Appearance
Python JSON 数据解析
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它易于人阅读和编写,同时也易于机器解析和生成。Python 提供了内置的 json 模块来处理 JSON 数据,本章节将详细介绍 JSON 的解析和生成。
JSON 基础
JSON 数据类型
JSON 支持以下数据类型:
- 对象(Object):用花括号
{}表示,包含键值对 - 数组(Array):用方括号
[]表示,包含值的列表 - 字符串(String):用双引号
""表示的文本 - 数字(Number):整数或浮点数
- 布尔值(Boolean):
true或false - 空值(Null):
null
JSON 示例
json
{
"name": "张三",
"age": 25,
"is_student": false,
"courses": ["数学", "英语", "物理"],
"address": {
"city": "北京",
"district": "海淀区"
},
"grades": null
}Python 中的 JSON 模块
Python 的 json 模块提供了以下主要函数:
json.dumps():将 Python 对象转换为 JSON 字符串json.dump():将 Python 对象转换为 JSON 字符串并写入文件json.loads():将 JSON 字符串转换为 Python 对象json.load():从文件中读取 JSON 字符串并转换为 Python 对象
JSON 与 Python 数据类型的对应关系
| JSON 类型 | Python 类型 |
|---|---|
| 对象(Object) | 字典(dict) |
| 数组(Array) | 列表(list) |
| 字符串(String) | 字符串(str) |
| 数字(Number) | 整数(int)或浮点数(float) |
| 布尔值(Boolean) | 布尔值(bool) |
| 空值(Null) | None |
JSON 序列化(Python → JSON)
使用 json.dumps()
python
import json
# Python 对象
data = {
"name": "张三",
"age": 25,
"is_student": False,
"courses": ["数学", "英语", "物理"],
"address": {
"city": "北京",
"district": "海淀区"
},
"grades": None
}
# 转换为 JSON 字符串
json_str = json.dumps(data)
print(f"JSON 字符串: {json_str}")
print(f"类型: {type(json_str)}")
# 美化输出
pretty_json = json.dumps(data, indent=2, ensure_ascii=False)
print(f"\n美化后的 JSON:\n{pretty_json}")
# 排序键
sorted_json = json.dumps(data, sort_keys=True, ensure_ascii=False)
print(f"\n排序后的 JSON:\n{sorted_json}")使用 json.dump()
python
import json
# Python 对象
data = {
"name": "张三",
"age": 25,
"is_student": False,
"courses": ["数学", "英语", "物理"],
"address": {
"city": "北京",
"district": "海淀区"
},
"grades": None
}
# 写入文件
with open('data.json', 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
print("JSON 文件已创建: data.json")
# 查看文件内容
with open('data.json', 'r', encoding='utf-8') as f:
print("\n文件内容:")
print(f.read())自定义对象序列化
对于自定义对象,需要定义一个序列化函数。
python
import json
# 自定义类
class Person:
"""人员类"""
def __init__(self, name, age, city):
"""初始化方法"""
self.name = name
self.age = age
self.city = city
# 序列化函数
def person_serializer(obj):
"""将 Person 对象转换为可序列化的字典"""
if isinstance(obj, Person):
return {
"name": obj.name,
"age": obj.age,
"city": obj.city,
"__class__": "Person"
}
raise TypeError(f"对象类型 {type(obj)} 不可序列化")
# 创建对象
person = Person("李四", 30, "上海")
# 序列化
json_str = json.dumps(person, default=person_serializer, indent=2, ensure_ascii=False)
print(f"序列化结果:\n{json_str}")
# 写入文件
with open('person.json', 'w', encoding='utf-8') as f:
json.dump(person, f, default=person_serializer, indent=2, ensure_ascii=False)
print("\nPerson 对象已序列化到 person.json")JSON 反序列化(JSON → Python)
使用 json.loads()
python
import json
# JSON 字符串
json_str = '''
{
"name": "张三",
"age": 25,
"is_student": false,
"courses": ["数学", "英语", "物理"],
"address": {
"city": "北京",
"district": "海淀区"
},
"grades": null
}
'''
# 转换为 Python 对象
data = json.loads(json_str)
print(f"Python 对象: {data}")
print(f"类型: {type(data)}")
# 访问数据
print(f"\n姓名: {data['name']}")
print(f"年龄: {data['age']}")
print(f"是否学生: {data['is_student']}")
print(f"课程: {data['courses']}")
print(f"城市: {data['address']['city']}")
print(f"年级: {data['grades']}")使用 json.load()
python
import json
# 从文件读取
with open('data.json', 'r', encoding='utf-8') as f:
data = json.load(f)
print(f"从文件读取的 Python 对象: {data}")
print(f"类型: {type(data)}")
# 访问数据
print(f"\n姓名: {data['name']}")
print(f"年龄: {data['age']}")
print(f"是否学生: {data['is_student']}")
print(f"课程: {data['courses']}")
print(f"城市: {data['address']['city']}")
print(f"年级: {data['grades']}")自定义对象反序列化
对于自定义对象,需要定义一个反序列化函数。
python
import json
# 自定义类
class Person:
"""人员类"""
def __init__(self, name, age, city):
"""初始化方法"""
self.name = name
self.age = age
self.city = city
def __repr__(self):
"""表示方法"""
return f"Person(name='{self.name}', age={self.age}, city='{self.city}')"
# 反序列化函数
def person_deserializer(dct):
"""将字典转换为 Person 对象"""
if "__class__" in dct and dct["__class__"] == "Person":
return Person(dct["name"], dct["age"], dct["city"])
return dct
# JSON 字符串
json_str = '''
{
"name": "李四",
"age": 30,
"city": "上海",
"__class__": "Person"
}
'''
# 反序列化
person = json.loads(json_str, object_hook=person_deserializer)
print(f"反序列化结果: {person}")
print(f"类型: {type(person)}")
print(f"姓名: {person.name}")
print(f"年龄: {person.age}")
print(f"城市: {person.city}")
# 从文件读取
with open('person.json', 'r', encoding='utf-8') as f:
person_from_file = json.load(f, object_hook=person_deserializer)
print(f"\n从文件反序列化: {person_from_file}")
print(f"类型: {type(person_from_file)}")JSON 解析的实际应用
示例 1:解析 API 响应
python
import json
import requests
# 调用 API
url = "https://api.github.com/users/octocat"
response = requests.get(url)
# 检查响应状态
if response.status_code == 200:
# 解析 JSON 响应
user_data = response.json() # 等同于 json.loads(response.text)
print(f"用户名: {user_data['login']}")
print(f"ID: {user_data['id']}")
print(f"名称: {user_data['name']}")
print(f"博客: {user_data['blog']}")
print(f"位置: {user_data['location']}")
print(f"关注者数: {user_data['followers']}")
print(f"关注数: {user_data['following']}")
print(f"创建时间: {user_data['created_at']}")
else:
print(f"API 调用失败: {response.status_code}")示例 2:生成配置文件
python
import json
# 配置数据
config = {
"database": {
"host": "localhost",
"port": 3306,
"user": "root",
"password": "password",
"name": "test_db"
},
"server": {
"host": "0.0.0.0",
"port": 8080,
"debug": True,
"timeout": 30
},
"logging": {
"level": "INFO",
"file": "app.log",
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
}
}
# 写入配置文件
with open('config.json', 'w', encoding='utf-8') as f:
json.dump(config, f, indent=2, ensure_ascii=False)
print("配置文件已创建: config.json")
# 读取配置文件
with open('config.json', 'r', encoding='utf-8') as f:
loaded_config = json.load(f)
print("\n读取的配置:")
print(f"数据库主机: {loaded_config['database']['host']}")
print(f"服务器端口: {loaded_config['server']['port']}")
print(f"日志级别: {loaded_config['logging']['level']}")示例 3:处理嵌套 JSON 数据
python
import json
# 嵌套 JSON 数据
nested_json = '''
{
"company": {
"name": "ABC公司",
"employees": [
{
"id": 1,
"name": "张三",
"position": "工程师",
"skills": ["Python", "Java", "C++"]
},
{
"id": 2,
"name": "李四",
"position": "产品经理",
"skills": ["产品设计", "用户研究", "数据分析"]
},
{
"id": 3,
"name": "王五",
"position": "设计师",
"skills": ["UI设计", "UX设计", "原型设计"]
}
],
"departments": ["技术部", "产品部", "设计部", "市场部"]
}
}
'''
# 解析 JSON
data = json.loads(nested_json)
# 访问嵌套数据
company_name = data['company']['name']
employees = data['company']['employees']
departments = data['company']['departments']
print(f"公司名称: {company_name}")
print(f"\n部门: {departments}")
print("\n员工信息:")
for employee in employees:
print(f"ID: {employee['id']}")
print(f"姓名: {employee['name']}")
print(f"职位: {employee['position']}")
print(f"技能: {employee['skills']}")
print()
# 查找特定员工
print("查找技能包含 Python 的员工:")
for employee in employees:
if "Python" in employee['skills']:
print(f"{employee['name']} (职位: {employee['position']})")示例 4:JSON 数据的修改和保存
python
import json
# 读取 JSON 文件
with open('data.json', 'r', encoding='utf-8') as f:
data = json.load(f)
print(f"原始数据: {data}")
# 修改数据
data['age'] = 26
data['is_student'] = True
data['courses'].append("化学")
data['address']['district'] = "朝阳区"
data['grades'] = {
"数学": 95,
"英语": 88,
"物理": 92,
"化学": 85
}
print(f"修改后的数据: {data}")
# 保存修改后的数据
with open('updated_data.json', 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
print("\n修改后的数据已保存到 updated_data.json")
# 查看修改后的文件
with open('updated_data.json', 'r', encoding='utf-8') as f:
print("\n修改后的文件内容:")
print(f.read())JSON 解析的最佳实践
1. 错误处理
在处理 JSON 数据时,应该捕获可能的异常:
python
import json
# 错误处理示例
json_str = '''
{
"name": "张三",
"age": 25,
"courses": ["数学", "英语", "物理"]
# 缺少逗号
"address": {
"city": "北京"
}
}
'''
try:
data = json.loads(json_str)
print(f"解析成功: {data}")
except json.JSONDecodeError as e:
print(f"JSON 解析错误: {e}")
except Exception as e:
print(f"其他错误: {e}")
# 文件读取错误处理
try:
with open('nonexistent.json', 'r', encoding='utf-8') as f:
data = json.load(f)
print(f"读取成功: {data}")
except FileNotFoundError:
print("文件不存在")
except json.JSONDecodeError as e:
print(f"JSON 解析错误: {e}")
except Exception as e:
print(f"其他错误: {e}")2. 美化输出
使用 indent 参数可以美化 JSON 输出,提高可读性:
python
import json
data = {
"name": "张三",
"age": 25,
"courses": ["数学", "英语", "物理"]
}
# 美化输出
pretty_json = json.dumps(data, indent=4, ensure_ascii=False, sort_keys=True)
print(f"美化后的 JSON:\n{pretty_json}")3. 处理 Unicode 字符
使用 ensure_ascii=False 参数可以正确处理 Unicode 字符:
python
import json
data = {
"name": "张三",
"message": "你好,世界!"
}
# 不使用 ensure_ascii
json_str1 = json.dumps(data)
print(f"使用 ensure_ascii=True: {json_str1}")
# 使用 ensure_ascii
json_str2 = json.dumps(data, ensure_ascii=False)
print(f"使用 ensure_ascii=False: {json_str2}")4. 处理大型 JSON 文件
对于大型 JSON 文件,可以使用 ijson 库进行流式解析,减少内存使用:
bash
pip install ijsonpython
import ijson
# 假设我们有一个大型 JSON 文件 'large_data.json'
# 示例内容: {"items": [{"id": 1, "name": "item1"}, {"id": 2, "name": "item2"}, ...]}
# 流式解析大型 JSON 文件
with open('large_data.json', 'r', encoding='utf-8') as f:
# 创建一个解析器
parser = ijson.parse(f)
# 遍历解析结果
for prefix, event, value in parser:
if prefix == "items.item" and event == "start_map":
# 开始一个新的 item
item = {}
elif prefix.endswith(".id") and event == "number":
# 解析 id
item["id"] = value
elif prefix.endswith(".name") and event == "string":
# 解析 name
item["name"] = value
elif prefix == "items.item" and event == "end_map":
# 完成一个 item 的解析
print(f"Item: {item}")5. 验证 JSON 格式
使用 jsonschema 库可以验证 JSON 数据是否符合特定的模式:
bash
pip install jsonschemapython
import json
from jsonschema import validate, ValidationError
# 定义 JSON Schema
schema = {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer", "minimum": 0},
"is_student": {"type": "boolean"},
"courses": {"type": "array", "items": {"type": "string"}},
"address": {
"type": "object",
"properties": {
"city": {"type": "string"},
"district": {"type": "string"}
},
"required": ["city", "district"]
}
},
"required": ["name", "age", "courses"]
}
# 验证有效的 JSON
data_valid = {
"name": "张三",
"age": 25,
"is_student": False,
"courses": ["数学", "英语", "物理"],
"address": {
"city": "北京",
"district": "海淀区"
}
}
try:
validate(instance=data_valid, schema=schema)
print("验证成功: 数据符合 Schema")
except ValidationError as e:
print(f"验证失败: {e}")
# 验证无效的 JSON
data_invalid = {
"name": "李四",
"age": -5, # 年龄为负数,不符合要求
"courses": ["数学", "英语"]
# 缺少 address
}
try:
validate(instance=data_invalid, schema=schema)
print("验证成功: 数据符合 Schema")
except ValidationError as e:
print(f"验证失败: {e}")总结
本章节介绍了 Python 中的 JSON 数据解析,包括:
- JSON 基础:JSON 数据类型和示例
- Python 中的 JSON 模块:
json.dumps(),json.dump(),json.loads(),json.load() - JSON 序列化:将 Python 对象转换为 JSON 字符串
- JSON 反序列化:将 JSON 字符串转换为 Python 对象
- 自定义对象序列化和反序列化:处理自定义类
- 实际应用示例:解析 API 响应、生成配置文件、处理嵌套 JSON 数据、修改和保存 JSON 数据
- 最佳实践:错误处理、美化输出、处理 Unicode 字符、处理大型 JSON 文件、验证 JSON 格式
掌握 JSON 解析技术,对于处理 API 响应、配置文件、数据交换等场景非常重要。通过合理使用 json 模块的功能,可以高效地处理各种 JSON 数据。