什么是JSON
JSON是比XML更简单的一种数据交换格式,它采用完全独立于编程语言的文本格式来存储和表示数据。
语法
使用键值对(key:value)表示对象的属性
使用逗号(,)分隔多条数据
使用花括号{ }表示对象
使用方括号[ ]表示数组
JSON键/值对
格式是:字段名称(包含在双引号中),后面加一个冒号,然后是值。
例如:"name": "XiaoHong"
JSON的值
数字(整数或浮点数)、字符串(在双引号中)、逻辑值(true 或 false)、数组(在方括号中)、对象(在花括号中)、null
JSON对象
对象表示为花括号{ }括起来的内容,数据结构为 { key:value, key:value, ... }的键值对的结构。
例如:{"name": "XiaoHong", "age":18}
JSON数组
数组表示为中括号[ ]括起来的内容,数据结构为 [字段1, 字段2, 字段3, ...],其中字段值的类型可以是数字、字符串、数组、对象几种。
例如: ["Python", "javascript", "C++", ...]
JSON vs XML
JSON的语法格式简单,层次结构清晰,比XML更易于阅读。另外,由于它占用的字符量少,用于网络数据传输时,能节约带宽,提高了传输效率。
JSON模块使用
json模块提供了Python对象的序列化和反序列化功能。
序列化:将一个Python对象编码转换为JSON字符串的过程。
反序列化:将JSON字符串解码转换为Python对象的过程。
1)无需安装,直接使用import json导入即可
2)四个方法:dumps、dump、loads、load,用于字符串和Python数据类型间进行转换。
其中,loads和load方法用于Python对象的反序列化,dumps和dump方法用于Python对象的序列化。
json.loads()方法 JSON格式字符串=>Python对象
|--------------|------------|
| JSON | Python |
| object | dict |
| array | list |
| string | unicode |
| number(int) | int,long |
| number(real) | float |
| true | True |
| false | False |
| null | None |
json.dumps()方法 Python对象=>JSON字符串 返回一个str对象。
|----------------|----------|
| Python | JSON |
| dict | object |
| list,tuple | array |
| str, unicode | string |
| int,long,float | number |
| True | true |
| False | false |
| None | null |
案例1:JSON字符串格式与Python对象的转换
python
import json
json_str = '{"name": "jack","age": 18}'
"""1. JSON字符串格式与Python对象的转换"""
print("=" * 60)
print("1. JSON字符串格式与Python对象的转换")
print("=" * 60)
# Python对象转JSON字符串 (序列化)
python_dict = {
"name": "张三",
"age": 25,
"city": "北京",
"hobbies": ["读书", "游泳", "编程"],
"is_student": False,
"score": None
}
# dumps: dict -> str
json_str = json.dumps(python_dict, ensure_ascii=False, indent=4)
print("Python字典转JSON字符串:")
print(json_str)
print()
# JSON字符串转Python对象 (反序列化)
json_string = '{"name": "李四", "age": 30, "city": "上海","is_student": false,"score": null}'
# loads: str -> dict
python_obj = json.loads(json_string)
print("JSON字符串转Python字典:")
print(f"类型: {type(python_obj)}, 内容: {python_obj}")
print()
# 其他Python对象转换
python_list = [1, 2, 3, "test", True, None]
json_from_list = json.dumps(python_list, ensure_ascii=False)
print(f"列表转JSON: {json_from_list}")
back_to_list = json.loads(json_from_list)
print(f"JSON转回列表: {back_to_list}")
print()
案例2:JSON文件格式的导入与导出
python
import json
"""2. JSON文件格式的导入与导出"""
print("=" * 60)
print("2. JSON文件格式的导入与导出")
print("=" * 60)
# 准备数据
data = {
"employees": [
{"id": 1, "name": "张三", "department": "技术部", "salary": 15000},
{"id": 2, "name": "李四", "department": "市场部", "salary": 12000},
{"id": 3, "name": "王五", "department": "技术部", "salary": 18000},
{"id": 4, "name": "赵六", "department": "人事部", "salary": 11000}
],
"company": "示例公司",
"year": 2026
}
# 导出JSON到文件
filename = "data.json"
with open(filename, 'w', encoding='utf-8') as f:
# dump: dict -> file
json.dump(data, f, ensure_ascii=False, indent=2)
print(f"数据已导出到 {filename}")
print()
# 从文件导入JSON
with open(filename, 'r', encoding='utf-8') as f:
# load: file -> dict
loaded_data = json.load(f)
print(f"从 {filename} 加载的数据:")
print(f"公司名称: {loaded_data['company']}")
print(f"员工数量: {len(loaded_data['employees'])}")
print(f"第一个员工: {loaded_data['employees'][0]['name']}")
print()
什么是JSONPath
JSONPath是一种信息抽取类库,是从JSON文档中抽取指定信息的工具,提供多种语言实现版本,包括:Javascript,Python,PHP和Java。
JSONPath的安装方法:pip install jsonpath -i https://mirrors.aliyun.com/pypi/simple/
JSON语法(对比XPath)
|-----------|--------------|----------------------------------------------|
| XPath | JSONPath | 描述 |
| / | $ | 根节点 |
| . | @ | 当前节点 |
| / | .or[] | 取子节点 |
| .. | 不支持 | 取父节点,JSONPath未支持 |
| // | .. | 就是不管位置,选择所有符合条件的节点 |
| * | * | 匹配所有元素节点 |
| @ | 不支持 | 根据属性访问,JSON不支持,因为JSON是个key-value递归结构,不需要属性访问 |
| [] | [] | 迭代器标示(可以在里边做简单的迭代操作,如数组下标,根据内容选值等) |
| | | [,] | 支持迭代器中做多选,并集 |
| [] | ?() | 支持过滤操作 |
| 不支持 | () | 支持表达式计算 |
| () | 不支持 | 分组,JSONPath不支持 |
案例3:JSONPath语法提取信息 - 基础
python
import json
import jsonpath
"""3. JSONPath语法提取信息 - 基础"""
print("=" * 60)
print("3. JSONPath语法提取信息")
print("=" * 60)
# 测试数据
data = {
"store": {
"book": [
{
"category": None,
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"category": "小说",
"author": " Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
},
{
"category": "小说",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{
"category": "小说",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"color": "红色",
"price": 19.95
}
}
}
print("测试数据结构:")
print(json.dumps(data, ensure_ascii=False, indent=2))
print(data)
print()
# 根节点与子节点处理
print("【根节点与子节点】")
# $ 表示根节点
# 修改后 - 添加错误检查
result = jsonpath.jsonpath(data, '$')
if result is False:
print("JSONPath 匹配失败,请检查数据和表达式")
else:
print(f"$ (根节点): {type(result)}, 内容: {result}")
# . 或 [] 访问子节点
result = jsonpath.jsonpath(data, '$.store')
print(f"$.store (store对象): {result}")
result = jsonpath.jsonpath(data, '$.store.bicycle')
print(f"$.store.bicycle (自行车信息): {result[0]['color']}")
print()
# 元素匹配与列表下标
print("【元素匹配与列表下标】")
# 获取所有书籍
result = jsonpath.jsonpath(data, '$.store.book.*')
print(f"$.store.book[*] (所有书籍): 共{len(result)}本")
# 获取第一本书
result = jsonpath.jsonpath(data, '$.store.book[0]')
print(result)
print(f"$.store.book[0] (第一本书): {result[0]['title']}")
# 获取最后一本书
result = jsonpath.jsonpath(data, '$.store.book[-1:]')
print(f"$.store.book[-1:] (最后一本书): {result[0]['title']}")
# 获取前两本书
result = jsonpath.jsonpath(data, '$.store.book[0:2]')
print(f"$.store.book[0:2] (前两本书): {[book['title'] for book in result]}")
# 获取所有书名
result = jsonpath.jsonpath(data, '$.store.book[*].title')
print(f"$.store.book[*].title (所有书名): {result}")
# 获取所有价格
result = jsonpath.jsonpath(data, '$..price')
print(f"$..price (所有价格): {result}")
print()
# 过滤条件
print("【过滤条件】")
# 过滤价格小于10的书籍
result = jsonpath.jsonpath(data, '$.store.book[?(@.price<10)]')
print(result)
print(f"价格<10的书籍: {[book['title'] for book in result]}")
# 过滤类别为"小说"的书籍
result = jsonpath.jsonpath(data, '$.store.book[?(@.category=="小说")]')
print(f"类别为'小说'的书籍: {[book['title'] for book in result]}")
# 过滤有ISBN的书籍
result = jsonpath.jsonpath(data, '$.store.book[?(@.isbn)]')
print(f"有ISBN的书籍: {[book['title'] for book in result]}")
# 递归搜索所有作者
result = jsonpath.jsonpath(data, '$..author')
print(f"$..author (所有作者): {result}")
print()
综合以上案例并深化
python
import json
import jsonpath
def demo_json_conversion():
"""1. JSON字符串格式与Python对象的转换"""
print("=" * 60)
print("1. JSON字符串格式与Python对象的转换")
print("=" * 60)
# Python对象转JSON字符串 (序列化)
python_dict = {
"name": "张三",
"age": 25,
"city": "北京",
"hobbies": ["读书", "游泳", "编程"],
"is_student": False,
"score": None
}
# dumps: dict -> str
json_str = json.dumps(python_dict, ensure_ascii=False, indent=4)
print("Python字典转JSON字符串:")
print(json_str)
print()
# JSON字符串转Python对象 (反序列化)
json_string = '{"name": "李四", "age": 30, "city": "上海","is_student": false,"score": null}'
# loads: str -> dict
python_obj = json.loads(json_string)
print("JSON字符串转Python字典:")
print(f"类型: {type(python_obj)}, 内容: {python_obj}")
print()
# 其他Python对象转换
python_list = [1, 2, 3, "test", True, None]
json_from_list = json.dumps(python_list, ensure_ascii=False)
print(f"列表转JSON: {json_from_list}")
back_to_list = json.loads(json_from_list)
print(f"JSON转回列表: {back_to_list}")
print()
def demo_json_file_io():
"""2. JSON文件格式的导入与导出"""
print("=" * 60)
print("2. JSON文件格式的导入与导出")
print("=" * 60)
# 准备数据
data = {
"employees": [
{"id": 1, "name": "张三", "department": "技术部", "salary": 15000},
{"id": 2, "name": "李四", "department": "市场部", "salary": 12000},
{"id": 3, "name": "王五", "department": "技术部", "salary": 18000},
{"id": 4, "name": "赵六", "department": "人事部", "salary": 11000}
],
"company": "示例公司",
"year": 2026
}
# 导出JSON到文件
filename = "data.json"
with open(filename, 'w', encoding='utf-8') as f:
# dump: dict -> file
json.dump(data, f, ensure_ascii=False, indent=2)
print(f"数据已导出到 {filename}")
print()
# 从文件导入JSON
with open(filename, 'r', encoding='utf-8') as f:
# load: file -> dict
loaded_data = json.load(f)
print(f"从 {filename} 加载的数据:")
print(f"公司名称: {loaded_data['company']}")
print(f"员工数量: {len(loaded_data['employees'])}")
print(f"第一个员工: {loaded_data['employees'][0]['name']}")
print()
def demo_jsonpath_basic():
"""3. JSONPath语法提取信息 - 基础"""
print("=" * 60)
print("3. JSONPath语法提取信息")
print("=" * 60)
# 测试数据
data = {
"store": {
"book": [
{
"category": None,
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"category": "小说",
"author": " Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
},
{
"category": "小说",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{
"category": "小说",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"color": "红色",
"price": 19.95
}
}
}
print("测试数据结构:")
print(json.dumps(data, ensure_ascii=False, indent=2))
print(data)
print()
# 根节点与子节点处理
print("【根节点与子节点】")
# $ 表示根节点
# 修改后 - 添加错误检查
result = jsonpath.jsonpath(data, '$')
if result is False:
print("JSONPath 匹配失败,请检查数据和表达式")
else:
print(f"$ (根节点): {type(result)}, 内容: {result}")
# . 或 [] 访问子节点
result = jsonpath.jsonpath(data, '$.store')
print(f"$.store (store对象): {result}")
result = jsonpath.jsonpath(data, '$.store.bicycle')
print(f"$.store.bicycle (自行车信息): {result[0]}")
print()
# 元素匹配与列表下标
print("【元素匹配与列表下标】")
# 获取所有书籍
result = jsonpath.jsonpath(data, '$.store.book.*')
print(f"$.store.book[*] (所有书籍): 共{len(result)}本")
# 获取第一本书
result = jsonpath.jsonpath(data, '$.store.book[0]')
print(result)
print(f"$.store.book[0] (第一本书): {result[0]['title']}")
# 获取最后一本书
result = jsonpath.jsonpath(data, '$.store.book[-1:]')
print(f"$.store.book[-1:] (最后一本书): {result[0]['title']}")
# 获取前两本书
result = jsonpath.jsonpath(data, '$.store.book[0:2]')
print(f"$.store.book[0:2] (前两本书): {[book['title'] for book in result]}")
# 获取所有书名
result = jsonpath.jsonpath(data, '$.store.book[*].title')
print(f"$.store.book[*].title (所有书名): {result}")
# 获取所有价格
result = jsonpath.jsonpath(data, '$..price')
print(f"$..price (所有价格): {result}")
print()
# 过滤条件
print("【过滤条件】")
# 过滤价格小于10的书籍
result = jsonpath.jsonpath(data, '$.store.book[?(@.price<10)]')
print(f"价格<10的书籍: {[book['title'] for book in result]}")
# 过滤类别为"小说"的书籍
result = jsonpath.jsonpath(data, '$.store.book[?(@.category=="小说")]')
print(f"类别为'小说'的书籍: {[book['title'] for book in result]}")
# 过滤有ISBN的书籍
result = jsonpath.jsonpath(data, '$.store.book[?(@.isbn)]')
print(f"有ISBN的书籍: {[book['title'] for book in result]}")
# 递归搜索所有作者
result = jsonpath.jsonpath(data, '$..author')
print(f"$..author (所有作者): {result}")
print()
def demo_jsonpath_advanced():
"""JSONPath高级用法"""
print("=" * 60)
print("4. JSONPath高级用法")
print("=" * 60)
data = {
"users": [
{"id": 1, "name": "张三", "age": 26, "city": "北京", "scores": [90, 85, 92]},
{"id": 2, "name": "李四", "age": 30, "city": "上海", "scores": [78, 88, 95]},
{"id": 3, "name": "王五", "age": 28, "city": "北京", "scores": [92, 91, 89]},
{"id": 4, "name": "赵六", "age": 35, "city": "广州", "scores": [85, 80, 82]},
{"id": 5, "name": "钱七", "age": 22, "city": "上海", "scores": [95, 93, 97]}
]
}
print("【多条件过滤】")
# 北京的且年龄大于25的用户
result = jsonpath.jsonpath(data, '$.users[?(@.city=="北京" & @.age>25)]')
print(f"北京且年龄>25: {result}")
# print(f"北京且年龄>25: {[user['name'] for user in result]}")
# 上海的或年龄小于25的用户
result = jsonpath.jsonpath(data, '$.users[?(@.city=="上海" | @.age<25)]')
# print(f"上海或年龄<25: {[user['name'] for user in result]}")
print()
print("【数组索引高级用法】")
# 获取前3个用户
result = jsonpath.jsonpath(data, '$.users[0:3]')
print(f"前3个用户: {[user['name'] for user in result]}")
# 获取最后2个用户
result = jsonpath.jsonpath(data, '$.users[-2:]')
print(f"最后2个用户: {[user['name'] for user in result]}")
# 获取特定索引的用户 (第1和第3个)
result = jsonpath.jsonpath(data, '$.users[0,2]')
print(f"第1和第3个用户: {[user['name'] for user in result]}")
print()
print("【嵌套数据访问】")
# 获取所有用户的第二个分数
result = jsonpath.jsonpath(data, '$.users[*].scores[1]')
print(f"所有用户的第二个分数: {result}")
# 获取第一个用户的所有分数
result = jsonpath.jsonpath(data, '$.users[0].scores[*]')
print(f"第一个用户的所有分数: {result}")
print()
print("【通配符使用】")
# 获取所有用户的所有信息
result = jsonpath.jsonpath(data, '$.users[*][*]')
print(f"所有用户的所有属性值 (扁平化): {result[:10]}...") # 只显示前10个
# 递归查找所有score相关
result = jsonpath.jsonpath(data, '$..scores')
print(f"所有scores数组: {result}")
def demo_practical_example():
"""实际应用示例"""
print("=" * 60)
print("5. 实际应用示例")
print("=" * 60)
# 模拟API返回的数据
api_response = {
"code": 200,
"message": "success",
"data": {
"total": 5,
"items": [
{"product_id": "P001", "name": "笔记本电脑", "price": 5999, "stock": 50, "category": "电子产品"},
{"product_id": "P002", "name": "鼠标", "price": 99, "stock": 200, "category": "配件"},
{"product_id": "P003", "name": "键盘", "price": 299, "stock": 150, "category": "配件"},
{"product_id": "P004", "name": "显示器", "price": 1999, "stock": 30, "category": "电子产品"},
{"product_id": "P005", "name": "耳机", "price": 399, "stock": 0, "category": "配件"}
]
}
}
# 保存到文件
with open('api_response.json', 'w', encoding='utf-8') as f:
json.dump(api_response, f, ensure_ascii=False, indent=2)
print("API响应数据已保存到 api_response.json")
print()
# 从文件读取
with open('api_response.json', 'r', encoding='utf-8') as f:
response = json.load(f)
print("【数据提取示例】")
# 检查响应状态
code = jsonpath.jsonpath(response, '$.code')[0]
message = jsonpath.jsonpath(response, '$.message')[0]
print(f"响应状态: {code}, 消息: {message}")
# 获取商品总数
total = jsonpath.jsonpath(response, '$.data.total')[0]
print(f"商品总数: {total}")
# 获取所有商品名称
names = jsonpath.jsonpath(response, '$.data.items[*].name')
print(f"所有商品: {names}")
# 获取有库存的商品
in_stock = jsonpath.jsonpath(response, '$.data.items[?(@.stock>0)]')
print(f"有库存的商品: {[item['name'] for item in in_stock]}")
# 获取缺货商品
out_of_stock = jsonpath.jsonpath(response, '$.data.items[?(@.stock==0)]')
print(f"缺货商品: {[item['name'] for item in out_of_stock]}")
# 获取电子产品类别的商品
electronics = jsonpath.jsonpath(response, '$.data.items[?(@.category=="电子产品")]')
print(f"电子产品: {[item['name'] for item in electronics]}")
# 获取价格大于500的商品
expensive = jsonpath.jsonpath(response, '$.data.items[?(@.price>500)]')
print(f"价格>500的商品: {[item['name'] for item in expensive]}")
# 计算平均价格
prices = jsonpath.jsonpath(response, '$.data.items[*].price')
avg_price = sum(prices) / len(prices)
print(f"平均价格: {avg_price:.2f}")
print()
print("【数据修改与保存】")
# 修改数据 - 给缺货商品补货
for item in response['data']['items']:
if item['stock'] == 0:
item['stock'] = 100
print(f"{item['name']} 已补货至 100 件")
# 保存修改后的数据
with open('api_response_updated.json', 'w', encoding='utf-8') as f:
json.dump(response, f, ensure_ascii=False, indent=2)
print("更新后的数据已保存到 api_response_updated.json")
if __name__ == '__main__':
# 运行所有示例
#demo_json_conversion()
#demo_json_file_io()
demo_jsonpath_basic()
# demo_jsonpath_advanced()
# demo_practical_example()
print("\n" + "=" * 60)
print("所有示例执行完成!")
print("=" * 60)