当前位置: 首页 > news >正文

《Python JSON 数据解析全指南:从基础到实战(含 jsonpath 与 Schema 验证)》

JSON数据解析

1.JSON基础概念

JSON 是一种轻量级的数据交换格式(另一个叫XML),具有简洁、易读的特点,并且在不同编程语言之间能很好地实现数据传递。在 Python 中,json模块能够实现 Python 数据类型与 JSON 数据格式之间的相互转换。

JSON的语法规则

  • 数据以键值对形式表示: "name": "张三"
  • 数据由逗号分隔
  • 花括号 {} 保存对象
  • 方括号 [] 保存数组
  • 支持的数据类型:
    • 数字(整数或浮点数)
    • 字符串(双引号中)
    • 布尔值(true 或 false)
    • 数组(方括号中)
    • 对象(花括号中)
    • null(None)
JSON 类型Python 类型
对象dict
数组list/tuple
字符串str
数字int/float
trueTrue
falseFalse
nullNone

JSON数据示例

{"name": "张三","age": 30,"isStudent": false,"courses": ["Python", "数据分析", "机器学习"],"address": {"city": "北京","postcode": "100000"},"phoneNumbers": null
}

json模块中的主要函数

函数描述
json.dumps()将Python对象编码成JSON字符串
json.dump()将Python对象编码成JSON字符串并写入文件
json.loads()将JSON字符串解码为Python对象
json.load()从文件中读取JSON字符串并解码为Python对象

2.JSON数据编码(序列化)

在实际开发中,为了让生成的 JSON 字符串更易读,可以使用indent参数进行缩进格式化,使用sort_keys参数按键名进行排序。

import json# 字典对象
data = {"name": "张三","age": 30,"isStudent": False,"courses": ["Python", "数据分析", "机器学习"],"address": {"city": "北京","postcode": "100000"},"phoneNumbers": None
}
# 将Python对象编码为JSON字符串
json_str = json.dumps(data, ensure_ascii=False)
print(json_str)
# 格式化输出
json_str = json.dumps(data, indent=4, ensure_ascii=False)
print(json_str)
json_str = json.dumps(data, indent=4, sort_keys=True, ensure_ascii=False)
print(json_str)# 写入到文件中
with open("data.json", "w", encoding="utf-8") as file:json.dump(data, file, ensure_ascii=False, indent=4, sort_keys=True)

3.JSON数据解码(反序列化)

import json
json_str = '{"name": "张三", "age": 30, "isStudent": false, "courses": ["Python", "数据分析", "机器学习"], "address": {"city": "北京", "postcode": "100000"}, "phoneNumbers": null}'
data = json.loads(json_str)
print(type(data))
print(data)
print(data['name'])
print(data['courses'][1])with open("data.json", 'r', encoding='utf-8') as file:data = json.load(file)print(data)print(type(data))

4.自定义编码器与解码器

标准的JSON只支持以下数据类型:

  • 字符串(string)
  • 数字(number)
  • 对象(object)- 在Python中表示为字典
  • 数组(array)- 在Python中表示为列表
  • 布尔值(boolean)- 在Python中表示为True/False
  • 空值(null)- 在Python中表示为None

然而,Python中有许多其他数据类型(如日期时间、自定义类、集合等)无法直接被JSON序列化。这就是为什么我们需要自定义编码器和解码器。

import json
import datetime
data = {"name": "张三","create_at": datetime.datetime.now(),"tags": {"Pythion", "JSON", "编程"}
}json_str = json.dumps(data, indent=4)
print(json_str)
# TypeError: Object of type set is not JSON serializable

自定义编码器

就是将Python中不能够直接编码为JSON格式的数据进行转换 转换成能够被JSON识别的数据

(1)使用default参数

最简单的自定义编码方式是使用 json.dumps() 的 default 参数:

import json
import datetime
data = {"name": "张三","create_at": datetime.datetime.now(),"tags": {"Pythion", "JSON", "编程"}
}# 编码函数:将非JSON类型的数据转换为JSON类型的数据
def custom_encoder(obj):if isinstance(obj, datetime.datetime):return obj.isoformat()elif isinstance(obj, set):return list(obj)json_str = json.dumps(data, indent=4, default=custom_encoder, ensure_ascii=False)
print(json_str)

(2)创建JSONEncoder子类

更灵活的方法是继承 json.JSONEncoder 类并重写 default 方法:

import json
import datetime
data = {"name": "张三","create_at": datetime.datetime.now(),"tags": {"Pythion", "JSON", "编程"}
}# 了解
class CustomJSONEncoder(json.JSONEncoder):def default(self, obj):if isinstance(obj, datetime.datetime):return {"__datetime__":True,"value":obj.isoformat()}elif isinstance(obj, set):return {"__set__": True, # 将数据原本的类型进行录入 为了给解码做提示"value":list(obj)}return super().default(obj)json_str = json.dumps(data, indent=4, cls=CustomJSONEncoder, ensure_ascii=False)
print(json_str)

自定义解码器

就是将某些JSON数据解码为原先的样子(Python数据类型)

(1)使用object_hook参数

json.loads() 函数的 object_hook 参数允许我们自定义JSON对象的解码方式:

import json
import datetime
json_str = """
{"name": "张三","create_at": {"__datetime__": true,"value": "2025-06-09T19:59:05.343916"},"tags": {"__set__": true,"value": ["编程","JSON","Pythion"]}
}
"""
# 自定义解码函数
def custom_decoder(obj):if "__datetime__" in obj:return datetime.datetime.fromisoformat(obj['value'])elif "__set__" in obj:return set(obj['value'])return objdata = json.loads(json_str, object_hook=custom_decoder)
print(data)

(2)创建JSONDecoder子类

更复杂的解码可以通过继承 json.JSONDecoder 类实现:

import json
import datetime
json_str = """
{"name": "张三","create_at": {"__datetime__": true,"value": "2025-06-09T19:59:05.343916"},"tags": {"__set__": true,"value": ["编程","JSON","Pythion"]}
}
"""
# 自定义解码类
class CustomJSONDecoder(json.JSONDecoder):# 构造函数def __init__(self, *args, **kwargs):json.JSONDecoder.__init__(self, object_hook=self.object_hook, *args, **kwargs)def object_hook(self,obj):if "__datetime__" in obj:return datetime.datetime.fromisoformat(obj['value'])elif "__set__" in obj:return set(obj['value'])return objdata = json.loads(json_str, cls=CustomJSONDecoder)
print(data)

5.处理复杂JSON数据

嵌套结构

{"company": "ABC科技","employees": [{"id": 1001,"name": "张三","department": "研发","skills": ["Python", "Django", "Docker"]},{"id": 1002,"name": "李四","department": "数据","skills": ["Python", "数据分析", "机器学习"]}],"address": {"city": "北京","street": "中关村","postcode": "100080"}
}
import json
json_str = '''
{"company": "ABC科技","employees": [{"id": 1001,"name": "张三","department": "研发","skills": ["Python", "Django", "Docker"]},{"id": 1002,"name": "李四","department": "数据","skills": ["Python", "数据分析", "机器学习"]}],"address": {"city": "北京","street": "中关村","postcode": "100080"}
}
'''
data = json.loads(json_str)
print(data['company'])
print(data['employees'][0]['name'])
print(data['employees'][1]['skills'][1])
for employee in data['employees']:print(employee['name'])print(employee['department'])print(employee['skills'])

动态解析路径

import json
json_str = '''
{"company": "ABC科技","employees": [{"id": 1001,"name": "张三","department": "研发","skills": ["Python", "Django", "Docker"]},{"id": 1002,"name": "李四","department": "数据","skills": ["Python", "数据分析", "机器学习"]}],"address": {"city": "北京","street": "中关村","postcode": "100080"}
}
'''
data = json.loads(json_str)path1 = "employees.0.name"
path2 = "address.city"def get_value_by_path(data, path):keys = path.split(".")result = datafor key in keys:if key.isdigit():result = result[int(key)]else:result = result[key]return resultprint(get_value_by_path(data, path1))
print(get_value_by_path(data, path2))
print(get_value_by_path(data, "employees.1.skills.2"))

6.拓展:jsonpath库

JSONPath提供了一种简洁的方式来导航JSON结构并提取特定数据,而不需要复杂的循环和条件语句。

pip install jsonpath-ng

基本语法元素

语法元素描述
$根对象/元素
@当前对象/元素
.子元素操作符
..递归下降操作符
*通配符,匹配所有对象/元素
[]下标操作符
[,]并集操作符
[start:end:step]数组切片操作符
?()过滤表达式
()脚本表达式

示例JSON数据

{"store": {"book": [{"category": "参考书","author": "李明","title": "Python编程入门","price": 49.99},{"category": "小说","author": "王芳","title": "梦想之旅","price": 29.99,"isbn": "0-553-21311-3"}],"bicycle": {"color": "红色","price": 599.99}}
}

示例路径演示

JSONPath描述
$.store.book[*].author所有书籍的作者
$..author所有作者
$.store.*store下的所有元素
$.store..pricestore下所有价格
$..book[2]第三本书
$..book[-1]最后一本书
$..book[0,1]前两本书
$..book[:2]前两本书
$..book[?(@.isbn)]所有有isbn属性的书
$..book[?(@.price<10)]所有价格小于10的书
$..book[?(@.price==8.95)]所有价格等于8.95的书
$..book[?(@.title =~ /.*REGEX.*/i)]标题匹配正则表达式的书

基本操作

import json
from jsonpath_ng import parse
json_str = """
{"store": {"book": [{"category": "参考书","author": "李明","title": "Python编程入门","price": 49.99},{"category": "小说","author": "王芳","title": "梦想之旅","price": 29.99,"isbn": "0-553-21311-3"}],"bicycle": {"color": "红色","price": 599.99}}
} """
data = json.loads(json_str)
# 导航对象
jsonpath_expr = parse('$.store.book[*].author')print(jsonpath_expr.find(data))# 列表
print(jsonpath_expr.find(data)[0]) # DatumInContext对象
print(type(jsonpath_expr.find(data)[0]))
for match in jsonpath_expr.find(data):print(match.value)print(match.path)print(match.context)

7.拓展:Schema验证

JSONSchema是一种用于验证JSON数据结构的规范,它允许我们定义JSON数据的格式、类型和约束条件,确保数据符合预期的结构和规则。

pip install jsonschema

JSONSchema是一种基于JSON格式的模式语言,用于:

  • 描述现有数据格式
  • 提供清晰的人机可读文档
  • 验证数据,确保数据质量
  • 自动测试和验证客户端提交的数据

核心关键字

关键字描述
$schema指定Schema的版本
titleSchema的标题
descriptionSchema的描述
type定义值的数据类型
properties定义对象的属性
required指定必需的属性
minimum/maximum数值的最小/最大值
minLength/maxLength字符串的最小/最大长度
pattern字符串必须匹配的正则表达式
enum枚举,值必须是指定的值之一
from jsonschema import validate# 定义一个JSON验证Schema
# 用户信息验证
user_schema = {"type": "object",  # 要求JSON整体是个JSON对象"properties": {  # 指定属性要求"name": {"type": "string"},  # 必须有一个name属性 string类型"age": {"type": "integer", "minimum": 0}, # 必须有一个age属性 int类型 最小0"email":{"type": "string", "format":"email"},"interests": {"type":"array", "items":{"type":"string"}}},"required":["name","age","email"]
}
user1  = {"name":"张三","age":30,"email":"zhangsan@qq.com","interests":["编程", "吃饭"]
}
user2  = {"name":"张三","age":30,"interests":["编程", "吃饭"]
}
user3 = {"name":"张三","age":30,"email":"zhangsan@qq.com",
}
user4 = {"name":"张三","age":"三十","email":"zhangsan@qq.com",
}
# 最好try-except
validate(instance=user1, schema=user_schema)
# validate(instance=user2, schema=user_schema) # 缺email
validate(instance=user3, schema=user_schema)
validate(instance=user4, schema=user_schema)

8.案例:头条新闻

import requestsdef print_news(title, uniquekey):# 1512-新闻详情查询 - 代码参考(根据实际业务情况修改)# 基本参数配置apiUrl = 'http://v.juhe.cn/toutiao/content'  # 接口请求URLapiKey = '3719af094e850cf3f4c4aea0bdb361d6'  # 在个人中心->我的数据,接口名称上方查看# 接口请求入参配置requestParams = {'key': apiKey,'uniquekey': uniquekey,}# 发起接口网络请求response = requests.get(apiUrl, params=requestParams)# 解析响应结果if response.status_code == 200:data = response.json()# 网络请求成功。可依据业务逻辑和接口文档说明自行处理。print("=" * 20)print(title)print(data['result']['content'])else:# 网络异常等因素,解析结果异常。可依据业务逻辑自行处理。print('请求异常')def search_news():# 923-新闻列表查询 - 代码参考(根据实际业务情况修改)# 基本参数配置apiUrl = 'http://v.juhe.cn/toutiao/index'  # 接口请求URLapiKey = '3719af094e850cf3f4c4aea0bdb361d6'  # 在个人中心->我的数据,接口名称上方查看# 接口请求入参配置requestParams = {'key': apiKey,'type': 'yule','page': 1,'page_size': 10,'is_filter': 0,}# 发起接口网络请求response = requests.get(apiUrl, params=requestParams)# 解析响应结果if response.status_code == 200:  # 404data = response.json()# 网络请求成功。可依据业务逻辑和接口文档说明自行处理。# print(data)# print(type(data))for item in data['result']['data']:print_news(item['title'], item['uniquekey'])else:# 网络异常等因素,解析结果异常。可依据业务逻辑自行处理。print('请求异常')search_news()
http://www.dtcms.com/a/278156.html

相关文章:

  • 九、官方人格提示词汇总(上)
  • 改进广告投入与销售额预测分析
  • CVE-2021-31201
  • 特征选择要解决什么问题
  • 算法题(174):全排列问题
  • 碳水循环(增肌、减脂)
  • AEC原理
  • 白盒测试方法深度解析:从理论到实践
  • Python协程进阶:优雅终止与异常处理详解
  • Mybatis 两级缓存可能导致的问题
  • 「小程序开发」新建页面设置启动页
  • alpinelinux的包管理
  • 力扣刷题记录(c++)09
  • ‘make_unique’ is not a member of ‘std’
  • win10下的wsl2扩充空间
  • 20250713 保存 PBM / PGM / PPM 图片 C++
  • 拼写纠错模型Noisy Channel(上)
  • 中华心法问答系统的解读(1)
  • XCZU2CG-2SFVC784I Xilinx FPGA AMD Zynq UltraScale+ MPSoC
  • if-constexpr,编译报错expected a “(“
  • JavaScript 中一些常见算法的实现及详细解析
  • 问题 E: Connecting Territories(DP)
  • 理解volatile:并发编程的核心机制
  • 能说说MyBatis的工作原理吗?
  • 柯西不等式
  • CATIA许可价格高,设计部门如何精细化分配?
  • 【时时三省】(C语言基础)通过指针引用数组元素2
  • 未来航空电子系统
  • 浮点数的乘法与除法运算耗时对比
  • 洛谷 P13014:[GESP202506 五级] 最大公因数