4、处理 JSON 数据:JSON 格式解析、Python 字典与 JSON 互转、使用 json() 方法提取数据。
好,咱们进入第四章。这一章聊的是 JSON,说白了就是 API 世界里最通用的“普通话”。你调用任何外部接口,十有八九返回的都是 JSON。不会处理它,后面的集成工作根本没法做。
我个人习惯把 JSON 理解成“轻量级的数据交换格式”。它长得跟 Python 的字典很像,但又不完全一样。很多新手一上来就混淆,觉得 JSON 就是字典,结果在类型转换上栽跟头。嗯,咱们今天就把这事彻底捋清楚。
4.1 JSON 格式长什么样?
先看一个最典型的 JSON 结构。假设我们调用了一个天气 API,返回的数据是这样的:
{
"city": "北京",
"temperature": 23,
"humidity": 65,
"wind": {
"direction": "东南风",
"speed": 3.5
},
"forecast": [
{"day": "周一", "temp_high": 25, "temp_low": 18},
{"day": "周二", "temp_high": 27, "temp_low": 20}
]
}
注意几个关键点:
- 键名必须用双引号,单引号不行。这是 JSON 和 Python 字典最大的区别之一。
- 字符串值也必须用双引号。
- 数字不需要引号,布尔值用
true/false(小写),空值用null。 - 支持嵌套,对象里套对象,对象里套数组,非常灵活。
核心认知:JSON 本质上就是一个字符串。它有自己的语法规则,跟 Python 的数据结构是两码事。你从 API 拿到的 JSON,必须先“解析”成 Python 能理解的东西,才能操作。
4.2 Python 字典与 JSON 互转
Python 标准库 json 提供了两个核心方法:json.dumps() 和 json.loads()。名字很好记,dumps 是“把字典 dump 成字符串”,loads 是“把字符串 load 成字典”。
4.2.1 JSON 字符串 → Python 字典(json.loads)
这是最常用的场景。你从 requests.get() 拿到响应文本,然后转成字典:
import json
json_str = '{"name": "张三", "age": 30, "is_student": false}'
data = json.loads(json_str)
print(data) # {'name': '张三', 'age': 30, 'is_student': False}
print(type(data)) # <class 'dict'>
print(data["name"]) # 张三
注意看,JSON 里的 false 变成了 Python 的 False,null 会变成 None。这个转换是自动的,你不需要手动处理。
我的经验:我曾经在解析一个金融接口时,对方返回的 JSON 里某个字段有时是字符串,有时是数字。直接用 json.loads 解析后,类型不一致导致后续计算报错。后来我加了一层类型校验,才把问题解决。所以,别太相信接口文档,实际数据可能跟你想象的不一样。
4.2.2 Python 字典 → JSON 字符串(json.dumps)
反过来,你要把数据发给 API 时,需要把字典转成 JSON 字符串:
import json
data = {
"name": "李四",
"age": 25,
"skills": ["Python", "Java", "Go"],
"is_active": True
}
json_str = json.dumps(data, ensure_ascii=False, indent=2)
print(json_str)
这里有两个参数值得注意:
ensure_ascii=False:让中文正常显示,而不是变成\uXXXX的编码。indent=2:格式化输出,方便调试时阅读。
输出效果:
{
"name": "李四",
"age": 25,
"skills": [
"Python",
"Java",
"Go"
],
"is_active": true
}
你看,Python 的 True 又变回了 JSON 的 true。这就是互转的对称性。
4.3 使用 json() 方法提取数据
如果你用的是 requests 库,有一个更省事的办法——直接用响应对象的 .json() 方法。它会自动帮你完成“读取响应体 → 解析 JSON → 返回字典”这一整套流程。
import requests
url = "https://api.example.com/user/123"
response = requests.get(url)
# 直接拿到字典
user_data = response.json()
print(user_data["name"])
print(user_data["email"])
这比先拿 response.text 再 json.loads() 要简洁得多。而且 .json() 内部做了编码处理,基本不会出现乱码问题。
注意:.json() 方法只有在响应内容确实是 JSON 格式时才有效。如果服务器返回了 500 错误页面或者 HTML,调用 .json() 会抛出 json.JSONDecodeError。我建议你在调用前先检查 response.status_code,或者用 try-except 包一下。
4.4 实战:处理嵌套 JSON
实际项目中的 JSON 往往嵌套很深。比如一个电商订单的返回数据:
{
"order_id": "ORD20241001",
"user": {
"id": 1001,
"name": "王五",
"address": {
"province": "广东",
"city": "深圳",
"detail": "南山区科技园"
}
},
"items": [
{"product_id": "P001", "name": "机械键盘", "price": 399, "quantity": 1},
{"product_id": "P002", "name": "鼠标垫", "price": 29.9, "quantity": 2}
],
"total": 458.8
}
要提取用户所在城市,你需要链式访问:
data = response.json()
city = data["user"]["address"]["city"]
print(city) # 深圳
要遍历商品列表,计算总价:
items = data["items"]
total = sum(item["price"] * item["quantity"] for item in items)
print(total) # 458.8
这里有个小技巧:如果你不确定某个键是否存在,用 .get() 方法更安全:
# 如果 "discount" 不存在,返回默认值 0
discount = data.get("discount", 0)
避坑指南:我曾经在解析一个日志分析系统的 API 时,对方返回的 JSON 里某个数组字段有时是 null,有时是空数组 []。直接用 for item in data["logs"] 遍历时,遇到 null 直接报错。后来我统一做了空值处理:logs = data.get("logs") or []。这个写法很实用,推荐给你。
4.5 本章知识体系
下面这张图帮你理清 JSON 处理的核心流程:
这张图展示了 JSON 处理的两条路径:从 API 拿到 JSON 字符串后,你可以用 json.loads() 或 .json() 把它变成 Python 字典,然后随心所欲地提取数据。处理完后,如果需要把数据发出去,再用 json.dumps() 转回 JSON 字符串。
4.6 总结
JSON 处理说白了就三件事:
- 读进来:用
json.loads()或.json()把字符串变字典。 - 写出去:用
json.dumps()把字典变字符串。 - 小心嵌套:链式访问时注意空值,多用
.get()和默认值。
这些操作在后续的 API 集成中会反复出现。你写多了就会发现,JSON 处理其实就那么几个套路,熟练了之后闭着眼睛都能写。
一个小建议:调试 JSON 数据时,我习惯先 print(json.dumps(data, indent=2, ensure_ascii=False)) 把结构打印出来看看。这样能快速了解数据长什么样,避免写错键名。这个习惯帮我省了不少排查时间。