当前位置: 首页 > 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.lryc.cn/news/587156.html

相关文章:

  • 002大模型基础知识
  • Opencv---blobFromImage
  • Llama系列:Llama1, Llama2,Llama3内容概述
  • 互联网大厂Java面试:从Spring Boot到微服务的场景应用
  • RHCIA第二次综合实验:OSPF
  • anaconda常用命令
  • 动态规划理论基础,LeetCode 509. 斐波那契数 LeetCode 70. 爬楼梯 LeetCode 746. 使用最小花费爬楼梯
  • 编译器优化——LLVM IR,零基础入门
  • 基础数论学习笔记
  • 每天学习一个Python第三方库之jieba库
  • vue中 js-cookie 用法
  • 深度学习算法:开启智能时代的钥匙
  • DVWA靶场通关笔记-XSS DOM(High级别)
  • 详解缓存淘汰策略:LFU
  • 初级网安作业笔记1
  • 3. 【Blazor全栈开发实战指南】--Blazor是什么?为什么选择Blazor?
  • [特殊字符]使用 Nginx 将 HTTP 重定向到 HTTPS
  • Spring-----MVC配置和基本原理
  • CD49.【C++ Dev】容器适配器模式
  • 一个链表节点构造函数的定义及使用
  • 如何将FPGA设计的验证效率提升1000倍以上(4)
  • Datawhale AI 夏令营【更新中】
  • 动态规划题解_零钱兑换【LeetCode】
  • 数学与应用数学核心课程有哪些?全文解析!
  • Cursor精准上下文指定
  • [Python 基础课程]字典
  • Spring AI 项目实战(十七):Spring Boot + AI + 通义千问星辰航空智能机票预订系统(附完整源码)
  • 12.3 安全内存区域划分
  • Kubernetes集群安装
  • Word中的批注显示与修订显示