Python访问JSON中subscription字段嵌套键值对的实现方法
问题根因
你无法读取subscription字段嵌套内容的核心原因是:导出users.json时,非空的subscription字段没有完成结构化序列化,直接以Python对象的字符串形式存入了JSON,因此读取JSON后该字段是str类型而非可直接键索引的字典对象;同时该字段存在空字符串的边界情况,未做判断直接解析会触发报错。
另外该字段的字符串内容包含ObjectId、datetime这类非标准JSON类型,无法直接用json.loads解析。
处理方案
按以下步骤处理即可正常访问嵌套内容:
- 遍历用户数组时先做空值判断,跳过空字符串或给空值设置默认结构,避免解析报错
- 用
ast.literal_eval做安全的字面量解析,将字符串形式的类字典结构转为真正的Python字典对象,该方法不会执行任意代码,比直接用eval安全 - 解析完成后即可直接通过键访问
subscription内部的嵌套值,若需要对ObjectId、datetime类型做后续计算,直接导入对应类处理即可
完整代码示例
import json import ast from bson import ObjectId from datetime import datetime # 读取现有JSON文件 with open("users.json", "r", encoding="utf-8") as f: users = json.load(f) for user in users: sub_raw = user.get("subscription", "") # 空值直接赋值为空字典,可根据业务需求调整为None if not isinstance(sub_raw, str) or len(sub_raw.strip()) == 0: user["subscription"] = {} continue # 安全解析字符串字典 try: sub_info = ast.literal_eval(sub_raw) # 替换原字段为解析后的字典 user["subscription"] = sub_info # 示例:访问嵌套字段 sub_id = sub_info.get("_id") # 类型为bson.ObjectId expire_time = sub_info.get("expire_at") # 类型为datetime.datetime print(f"用户ID {user.get('user_id')} 订阅信息:订阅ID {sub_id},到期时间 {expire_time}") except (SyntaxError, ValueError): # 解析失败的异常数据打日志后赋值默认值,避免程序中断 print(f"用户ID {user.get('user_id')} subscription字段格式异常,原始值:{sub_raw}") user["subscription"] = {}
后续优化建议
如果处理完数据需要重新导出为标准JSON,需要自定义序列化函数处理特殊类型,避免JSON序列化报错:
def custom_serializer(obj): if isinstance(obj, datetime): return obj.isoformat() if isinstance(obj, ObjectId): return str(obj) raise TypeError(f"不支持序列化的类型:{type(obj)}") # 导出解析后的标准JSON with open("users_parsed.json", "w", encoding="utf-8") as f: json.dump(users, f, ensure_ascii=False, indent=2, default=custom_serializer)
注意事项
- 禁止直接使用
eval()解析该字段,若字符串中包含恶意代码会直接被执行,存在严重安全风险 - 若部分字段解析失败,可打印原始字符串排查格式问题,比如存在多余引号、转义字符时可先做字符串清洗再解析
内容的提问来源于stack exchange,提问作者rachel787
相关产品推荐
相关产品推荐

