Python JSON数据处理教程

JSON在Python里就是个字典套字典的格式,标准库json直接可用,不用装第三方包。日常处理无非就是:读、写、解析、校验、序列化。下面直接上代码,边写边解释坑。 1. 基础读写
import json

# Python对象转JSON字符串
data = {"name": "张三", "age": 25, "skills": ["Python", "Go"]}
json_str = json.dumps(data, ensure_ascii=False)  # ensure_ascii=False让中文正常显示
print(json_str)  # {"name": "张三", "age": 25, "skills": ["Python", "Go"]}

# JSON字符串转Python对象
parsed = json.loads(json_str)
print(parsed["name"])  # 张三
写入文件用dump,读取用load,别记混了:
# 写入文件
with open("data.json", "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False, indent=2)  # indent格式化输出

# 读取文件
with open("data.json", "r", encoding="utf-8") as f:
    loaded = json.load(f)
2. 处理复杂嵌套结构 实际项目里JSON经常长这样:
resp = {
    "code": 200,
    "data": {
        "users": [
            {"id": 1, "name": "Alice", "address": {"city": "Beijing"}},
            {"id": 2, "name": "Bob", "address": {"city": "Shanghai"}}
        ],
        "total": 2
    }
}

# 安全取值,避免KeyError
users = resp.get("data", {}).get("users", [])
for user in users:
    city = user.get("address", {}).get("city", "unknown")
    print(f"{user['name']} lives in {city}")
get方法配合空字典{}可以链式取值,比直接抛KeyError优雅得多。 3. 处理非法JSON 从外部接口拿到的JSON经常有单引号、尾逗号、注释,标准json.loads会直接报错。用demjson3或json5库可以宽容解析:
pip install demjson3
import demjson3

bad_json = "{'name': '张三', 'age': 25,}"  # 单引号+尾逗号
parsed = demjson3.decode(bad_json)
print(parsed)  # {'name': '张三', 'age': 25}
如果不想装第三方库,可以手动清洗:
import re

def clean_json(raw):
    raw = re.sub(r"'", '"', raw)  # 单引号转双引号
    raw = re.sub(r",\s*}", "}", raw)  # 去掉对象尾逗号
    raw = re.sub(r",\s*]", "]", raw)  # 去掉数组尾逗号
    raw = re.sub(r"//.*", "", raw)  # 去掉行注释
    return raw

raw = "{'name': '张三', 'age': 25,}"  # 单引号+尾逗号
safe = clean_json(raw)
print(json.loads(safe))  # {'name': '张三', 'age': 25}
4. 自定义序列化 遇到datetime、Decimal这类Python原生类型,json.dumps会报TypeError。用default参数处理:
from datetime import datetime
from decimal import Decimal

class CustomEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.strftime("%Y-%m-%d %H:%M:%S")
        if isinstance(obj, Decimal):
            return float(obj)
        return super().default(obj)

data = {"time": datetime.now(), "price": Decimal("19.99")}
print(json.dumps(data, cls=CustomEncoder))
# {"time": "2025-03-15 14:30:00", "price": 19.99}
5. 大文件流式处理 几GB的JSON文件不能一次性load到内存,用ijson或json.load分段处理:
pip install ijson
import ijson

# 假设文件是 [{...}, {...}, ...] 这种数组格式
with open("huge.json", "r", encoding="utf-8") as f:
    parser = ijson.parse(f)
    for prefix, event, value in parser:
        if prefix.endswith("name") and event == "string":
            print(value)  # 只读name字段,内存占用极小
如果JSON是每行一个对象(JSON Lines格式),直接逐行读:
with open("lines.json", "r") as f:
    for line in f:
        line = line.strip()
        if line:
            obj = json.loads(line)
            # 处理单个对象
6. 验证JSON Schema 接口返回的数据结构可能变化,用jsonschema库做校验:
pip install jsonschema
from jsonschema import validate, ValidationError

schema = {
    "type": "object",
    "required": ["name", "age"],
    "properties": {
        "name": {"type": "string"},
        "age": {"type": "integer", "minimum": 0}
    }
}

data = {"name": "张三", "age": -1}
try:
    validate(instance=data, schema=schema)
except ValidationError as e:
    print(f"校验失败: {e.message}")
7. 性能优化 频繁调用json.dumps/loads时,用orjson替换标准库,速度能快5-10倍:
pip install orjson
import orjson

data = {"name": "张三", "age": 25}
json_bytes = orjson.dumps(data, option=orjson.OPT_INDENT_2)  # 返回bytes
print(json_bytes.decode("utf-8"))

parsed = orjson.loads(json_bytes)
print(parsed)
注意orjson返回的是bytes,不是str,解码一下即可。 8. 实际场景:API数据持久化 从雨云服务器拉取监控数据并本地存储:
import requests
import json
from pathlib import Path

def fetch_and_save(api_url, token, save_path):
    headers = {"Authorization": f"Bearer {token}"}
    resp = requests.get(api_url, headers=headers, timeout=10)
    resp.raise_for_status()
    
    data = resp.json()  # 自动解析响应JSON
    
    # 只保留需要的字段
    filtered = {
        "status": data.get("status"),
        "metrics": data.get("metrics", {}).get("cpu", [])
    }
    
    # 原子写入,防止写入一半崩溃导致文件损坏
    temp_path = save_path.with_suffix(".tmp")
    with open(temp_path, "w", encoding="utf-8") as f:
        json.dump(filtered, f, ensure_ascii=False, indent=2)
    temp_path.rename(save_path)
    
    return filtered

# 雨云服务器API示例
data = fetch_and_save(
    "https://api.rainyun.com/v1/monitor",
    "your_token_here",
    Path("/data/monitor.json")
)
雨云的API稳定性和响应速度都不错,配合json持久化做数据归档很省心。 常见坑总结 – json.loads默认不处理单引号,记得用demjson或手动替换 – 文件读写指定encoding=”utf-8″,否则Windows上中文乱码 – 大JSON不要用json.load全量读,用ijson或逐行解析 – 浮点数精度问题:用Decimal先转字符串再序列化 – 字典顺序:Python 3.7+字典保持插入顺序,json.dumps默认按key排序,加sort_keys=False关掉

雨云是国内一家老牌云服务商,提供高性价比的云服务器和虚拟主机。我用它部署了好几个项目,速度和稳定性都不错。通过 https://www.rainyun.com/SAJA_ 注册可以领一张 5折优惠券,有需要的朋友可以看看。

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容