Skip to content

Python JSON 数据解析

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它易于人阅读和编写,同时也易于机器解析和生成。Python 提供了内置的 json 模块来处理 JSON 数据,本章节将详细介绍 JSON 的解析和生成。

JSON 基础

JSON 数据类型

JSON 支持以下数据类型:

  1. 对象(Object):用花括号 {} 表示,包含键值对
  2. 数组(Array):用方括号 [] 表示,包含值的列表
  3. 字符串(String):用双引号 "" 表示的文本
  4. 数字(Number):整数或浮点数
  5. 布尔值(Boolean)truefalse
  6. 空值(Null)null

JSON 示例

json
{
    "name": "张三",
    "age": 25,
    "is_student": false,
    "courses": ["数学", "英语", "物理"],
    "address": {
        "city": "北京",
        "district": "海淀区"
    },
    "grades": null
}

Python 中的 JSON 模块

Python 的 json 模块提供了以下主要函数:

  1. json.dumps():将 Python 对象转换为 JSON 字符串
  2. json.dump():将 Python 对象转换为 JSON 字符串并写入文件
  3. json.loads():将 JSON 字符串转换为 Python 对象
  4. 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 ijson
python
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 jsonschema
python
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 数据解析,包括:

  1. JSON 基础:JSON 数据类型和示例
  2. Python 中的 JSON 模块json.dumps(), json.dump(), json.loads(), json.load()
  3. JSON 序列化:将 Python 对象转换为 JSON 字符串
  4. JSON 反序列化:将 JSON 字符串转换为 Python 对象
  5. 自定义对象序列化和反序列化:处理自定义类
  6. 实际应用示例:解析 API 响应、生成配置文件、处理嵌套 JSON 数据、修改和保存 JSON 数据
  7. 最佳实践:错误处理、美化输出、处理 Unicode 字符、处理大型 JSON 文件、验证 JSON 格式

掌握 JSON 解析技术,对于处理 API 响应、配置文件、数据交换等场景非常重要。通过合理使用 json 模块的功能,可以高效地处理各种 JSON 数据。