如何将API返回的嵌套JSON解析为Pandas DataFrame?
嵌套JSON转Pandas DataFrame的实现方案
我经常遇到这种嵌套JSON转DataFrame的需求,给你一套实用的解决方案,分情况来看:
首先咱们先明确你的数据结构——应该是类似「城市代码→多条线路→每条线路对应多个站点」的三层嵌套,我先模拟一个和你场景匹配的JSON示例,方便你对应自己的实际数据:
# 模拟API返回的嵌套JSON数据 api_response = [ { "city_code": "BJ", "lines": [ { "line_name": "1号线", "stations": ["苹果园", "古城", "八角游乐园"] }, { "line_name": "2号线", "stations": ["西直门", "车公庄", "阜成门"] } ] }, { "city_code": "SH", "lines": [ { "line_name": "1号线", "stations": ["莘庄", "外环路", "莲花路"] } ] } ]
一、基础场景:站点是纯列表(无额外属性)
这种情况用**pd.json_normalize + explode**就能快速解决,是最简洁的最优解:
步骤1:展开线路层级
先用json_normalize把外层的城市代码和内层的线路信息关联起来,把lines数组展开成单独的行:
import pandas as pd # 展开线路,保留城市代码作为元数据 df_lines = pd.json_normalize(api_response, record_path="lines", meta=["city_code"])
这时候得到的df_lines会有三列:line_name、stations(列表格式)、city_code。
步骤2:展开站点列表
用explode把stations列的列表拆分成单独的行,每个站点对应一行数据:
df_final = df_lines.explode("stations").reset_index(drop=True)
最终的df_final就是每行对应「城市代码→线路名称→单个站点」的扁平结构,完全符合数据分析的需求。
二、进阶场景:站点包含额外属性(如站点代码、坐标)
如果你的站点不是纯字符串列表,而是带属性的字典列表(比如{"station_name": "苹果园", "station_code": "APY"}),可以直接用json_normalize的多级record_path一次性展开:
示例JSON(带站点属性)
api_response_advanced = [ { "city_code": "BJ", "lines": [ { "line_name": "1号线", "stations": [ {"station_name": "苹果园", "station_code": "APY"}, {"station_name": "古城", "station_code": "GC"} ] } ] } ]
实现代码
df_final = pd.json_normalize( api_response_advanced, record_path=["lines", "stations"], # 直接指定到最内层的站点数组 meta=["city_code", ["lines", "line_name"]] # 保留外层的城市代码和线路名称 ) # 重命名冗余的列名,让结果更清晰 df_final.rename(columns={"lines.line_name": "line_name"}, inplace=True)
这样就能直接得到包含city_code、line_name、station_name、station_code的完整扁平DataFrame。
三、推荐函数与注意事项
核心函数推荐
pd.json_normalize():处理嵌套JSON的核心工具,支持指定record_path展开内层数组,meta保留外层关联字段,几乎能覆盖绝大多数嵌套场景。DataFrame.explode():专门用来将列表类型的列拆分成多行,操作简单且性能优异,适合处理纯列表形式的嵌套数据。- 若遇到极复杂的嵌套结构(比如多层递归嵌套),可以结合
itertools.chain或自定义递归函数来扁平化,但这种场景很少见,优先用内置函数。
注意事项
- 如果API返回的是单个字典而非列表(比如
{"city_code": "BJ", "lines": [...]}),需要先把它转成列表再传入json_normalize:pd.json_normalize([api_response])。 - 若存在缺失值(比如某条线路没有站点),
explode会生成空值行,可以用df_final.dropna(subset=["stations"])过滤掉。 - 可以通过
json_normalize的errors参数控制错误处理(比如errors="ignore"忽略解析错误)。
内容的提问来源于stack exchange,提问作者Aegis
相关产品推荐
相关产品推荐

