pandas json_normalize展平嵌套字典时record_path报KeyError
pandas展平嵌套JSON报KeyError: 'facilities'排查与解决
问题场景
处理AGSI公共API返回的JSON数据,目标是将嵌套的存储设施数据展平为单设施单行的结构化表,公司维度属性作为元数据附加到对应行。原有可正常运行的pd.json_normalize代码近日抛出键不存在错误,已人工确认业务数据中均存在facilities字段,无法定位问题。
待处理JSON结构(节选)
json = {'Austria': [{'image': 'iVBORw0KxuOmB00wGjmw4Y3XTA=', 'short_name': 'astora', 'name': 'astora GmbH', 'url': 'http://www.astora.de', 'eic': '21X000000001160J', 'facilities': [{'eic': '21W000000000078N', 'name': 'UGS Haidach (astora)', 'country': {'code': 'AT', 'name': 'Austria'}, 'type': 'Storage Facility'}], 'data': {'type': 'SSO', 'country': {'code': 'AT', 'name': 'Austria'}, 'code': 'EU', 'name': 'Europe'}}, # 其余奥地利公司条目省略 ]}
原有实现代码
Austria = pd.json_normalize(json, record_path="facilities", meta=["name", "type", "eic"], meta_prefix='company_').drop(["url"], axis=1)
报错信息
KeyError: "Key 'facilities' not found. If specifying a record_path, all elements of data should have the path."
问题根源
报错核心原因是传入json_normalize的数据层级错误:
- 该JSON顶层是国家名到公司列表的映射字典,
facilities字段存在于每个公司条目中,不存在于顶层字典的键中 - 之前代码可运行是因为传入的是
json['Austria'](公司列表层级),本次运行直接传入了整个顶层字典,pandas遍历顶层键(国家名字符串)查找facilities字段,自然触发键不存在错误 - 人工校验字段时检查的是公司列表内的条目,和pandas实际遍历的对象不一致,因此没发现问题
额外原有代码隐患:meta参数中传入的type字段不属于公司层级属性,公司条目下无该字段,修正入参后也会触发键错误,type实际存在于facilities子项和data嵌套结构中。
修复方案
单国家数据处理
明确传入对应国家的公司列表层级,同时修正meta参数为公司层级实际存在的字段,嵌套字段用列表形式声明路径:
import pandas as pd Austria = pd.json_normalize( json["Austria"], # 传入公司列表,而非整个顶层JSON record_path="facilities", meta=[ "name", "short_name", "eic", "url", ["data", "type"], ["data", "code"] ], meta_prefix="company_" )
全国家批量处理
先遍历顶层字典汇总所有国家的公司条目,再统一展平,可额外保留国家名称字段避免信息丢失:
all_companies = [] for country_name, company_list in json.items(): for company in company_list: company["belong_country"] = country_name all_companies.append(company) full_df = pd.json_normalize( all_companies, record_path="facilities", meta=[ "name", "short_name", "eic", "url", "belong_country", ["data", "type"], ["data", "code"] ], meta_prefix="company_" )
异常定位校验脚本
如果修正入参后仍报字段缺失错误,可运行以下脚本快速定位异常条目:
# 以奥地利数据为例 for idx, company in enumerate(json["Austria"]): if "facilities" not in company: print(f"索引{idx}的公司缺失facilities字段,公司名:{company.get('name', '未知')}") if not isinstance(company.get("facilities"), list): print(f"索引{idx}的公司facilities字段格式不是列表,公司名:{company.get('name', '未知')}")
内容的提问来源于stack exchange,提问作者el-don-quijote
相关产品推荐
相关产品推荐

