You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python解析API返回单键嵌套JSON为字典并转DataFrame

问题根因

之前的解析方案存在三个典型错误:

  • 错误使用ndjson处理返回结果:该接口返回标准单块JSON,ndjson仅适用于换行分隔的多段JSON流,场景完全错配
  • 归一化时未定位到实际数据路径:直接对顶层返回对象做json_normalize,只会拿到唯一顶层键drugMemberGroup,无法触达内部嵌套的药品数组
  • 重复json.loads/json.dumps操作不会改变JSON的嵌套结构,无法解决路径定位错误的核心问题

处理步骤

1. 基础请求与JSON加载

不要做多余的格式转换,urllib3返回的响应是bytes类型,直接解码为UTF-8字符串后单次加载即可:

import urllib3
import json
import pandas as pd
from pandas import json_normalize

# 初始化连接池
http = urllib3.PoolManager()
req_url = "https://rxnav.nlm.nih.gov/REST/rxclass/classMembers.json?classId=C&relaSource=ATC&trans=0"
resp = http.request("GET", req_url)

# 单次加载JSON,不要重复做dumps/loads操作
resp_data = json.loads(resp.data.decode("utf-8"))

2. 定位目标数据数组

接口返回的326条药品记录实际存储在drugMemberGroup.drugMember路径下,先提取该数组做校验:

# 提取药品记录数组
drug_records = resp_data["drugMemberGroup"]["drugMember"]
# 校验长度,正常返回326
print(f"获取到药品记录数:{len(drug_records)}")

3. 转换为可操作字典

如果需要扁平化的字典列表,直接遍历提取字段即可,把minConcept下的核心字段提升到外层,保留nodeAttr属性数组:

formatted_drug_dict = []
for record in drug_records:
    # 提取minConcept下的rxcui、药品名称、tty字段
    drug_base = record["minConcept"].copy()
    # 保留属性数组和其他顶层字段
    drug_base["nodeAttr"] = record.get("nodeAttr", [])
    for key, val in record.items():
        if key not in ["minConcept", "nodeAttr"]:
            drug_base[key] = val
    formatted_drug_dict.append(drug_base)

4. 转换为规整pandas DataFrame

根据是否需要展开nodeAttr属性数组,选择对应方案:

方案A:不展开属性数组,保留为列值

直接使用json_normalize展平minConcept嵌套结构,nodeAttr以数组形式存在列中:

df = json_normalize(
    drug_records,
    meta=["nodeAttr"],
    record_prefix="drug_"
)
# 重命名列更易读
df = df.rename(columns={
    "drug_rxcui": "rxcui",
    "drug_name": "drug_name",
    "drug_tty": "tty"
})

方案B:展开属性数组为规整长表

如果需要把nodeAttr中存储的药品属性(如ATC编码、定义等)展平为单独列,做二次归一化即可:

# 先展平第一层嵌套
df = json_normalize(drug_records)
# 清理列名
df.columns = [col.replace("minConcept.", "") for col in df.columns]
# 炸开nodeAttr数组
df = df.explode("nodeAttr").reset_index(drop=True)
# 展平nodeAttr内的属性字段
attr_cols = json_normalize(df["nodeAttr"]).add_prefix("attr_")
# 拼接得到最终宽表
df = pd.concat([df.drop(columns=["nodeAttr"]), attr_cols], axis=1)

常见报错排查

  • KeyError: 'drugMember':先打印resp_data.keys()检查返回结构,通常是请求参数传错(如classId、relaSource拼写错误)导致接口返回错误响应
  • 类型报错list indices must be integers or slices, not str:检查取值路径,不要跳过drugMemberGroup层级直接取drugMember
  • JSON解析报错:确认响应状态码为200,不要对异常响应(如404、500的HTML页面)做JSON加载

内容的提问来源于stack exchange,提问作者user1470034

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.19 16:15:46