Python嵌套JSON展开打平教程:扁平化嵌套字段
把深层嵌套的JSON数据用json_normalize或递归函数打平成扁平表,点号路径作为列名,方便转CSV和做分析,附完整代码。
场景痛点
接口返回的JSON一层套一层:user.profile.address.city、order.items[0].sku,直接转CSV只能把嵌套字段塞成一坨字符串。想把 city、sku 单独拉成列做筛选统计,就得先把嵌套结构"打平"。这篇用pandas的 json_normalize 和递归两种方式解决。
用到的库
pip install pandas
完整代码
# 嵌套JSON展开打平
import json
import pandas as pd
def flatten_with_json_normalize(json_path):
"""
用pandas自带的json_normalize,自动把嵌套dict展开成点号列名。
record_path 指定数组路径,meta 指定要带上的父级字段。
"""
with open(json_path, "r", encoding="utf-8") as f:
data = json.load(f)
# 情况1:根就是list[dict],直接打平
if isinstance(data, list):
df = pd.json_normalize(data)
else:
# 情况2:根是dict,里面有个数组需要展开
# 比如 {"orders": [{"user": {...}, "items": [...]}]}
# record_path 指向要展开的数组路径
df = pd.json_normalize(
data,
record_path="orders", # 展开 orders 数组
meta=["user_id", "shop_id"], # 把外层字段也带上
errors="ignore",
)
print("打平后列名:")
for c in df.columns:
print(" ", c)
print(f"\n形状:{df.shape}")
return df
def flatten_recursive(nested_dict, parent_key="", sep="."):
"""
递归手动打平,适定制灵活。
把 {"a": {"b": 1}} 变成 {"a.b": 1}
"""
items = {}
for k, v in nested_dict.items():
new_key = f"{parent_key}{sep}{k}" if parent_key else k
if isinstance(v, dict):
items.update(flatten_recursive(v, new_key, sep=sep))
elif isinstance(v, list):
# 列表类型:转成JSON字符串存着,或展开成多列
items[new_key] = json.dumps(v, ensure_ascii=False)
else:
items[new_key] = v
return items
def flatten_list_records(records):
"""对list[dict]批量递归打平。"""
flat = [flatten_recursive(r) for r in records]
return pd.DataFrame(flat)
def main():
json_file = "nested.json"
print("=== json_normalize 方式 ===")
df1 = flatten_with_json_normalize(json_file)
df1.to_csv("flatten_normalize.csv", index=False, encoding="utf-8-sig")
print("\n=== 递归方式(示例数据)===")
sample = [
{
"user": {"id": 1, "name": "张三", "address": {"city": "北京", "zip": "100000"}},
"order": {"id": 100, "amount": 299.5, "items": [{"sku": "A1"}, {"sku": "A2"}]},
},
{
"user": {"id": 2, "name": "李四", "address": {"city": "上海"}},
"order": {"id": 101, "amount": 599.0},
},
]
df2 = flatten_list_records(sample)
print(df2.T)
df2.to_csv("flatten_recursive.csv", index=False, encoding="utf-8-sig")
if __name__ == "__main__":
main()
代码讲解
pd.json_normalize(data)是官方推荐,自动把嵌套dict展开成user.address.city这种点号列名。record_path指定哪个数组要"炸开",meta指定哪些父级字段要平铺到每行。- 递归方式更灵活,遇到list就序列化成JSON字符串,遇到dict继续往下钻。
- 打平后列名很长但清晰,
df["user.address.city"]直接取城市列。 - 两种方式都输出CSV,打开就是扁平表格。
运行结果
控制台打印打平后的列名和表形状。当前目录生成两个CSV:flatten_normalize.csv 来自文件,flatten_recursive.csv 来自示例数据。嵌套字段全部变成顶层列,列表字段是JSON字符串。
注意事项
- 数组里嵌套对象(比如
items: [{sku:1}, {sku:2}])不会自动拆成多行,要拆多行得先explode再normalise。 - 列名带点号在pandas里访问用
df["user.address.city"],不要用属性访问df.user.address。 - 超深嵌套(10层以上)列名会非常长,按需
rename缩短关键列。 - 递归方式遇到循环引用会爆栈,正常API数据不会有这问题。

更新时间:2026-09-14 20:58:40
上一篇:Python处理异常值outliers检测与处理教程