与第三方API接口对接的时候,是经常会遇到多层嵌套的json的,而我们需要的数据可能仅仅是某几个,或者是需要转换成二维表用来存入数据库。通常我都是用遍历来一遍一遍的for循环获取,但这样效率差劲不说,代码还显得特别low,今天安利一个非常快捷的工具给大家---pd.json_normalize。
首先导入相关库
import pandas as pd
from pandas.io.json import json_normalize
设定一个json
df = {
"error": 0,
"status": "success",
"results": [
{
"currentCity": "青岛",
"index": [
{
"title": "穿衣",
"zs": "较冷",
"tipt": "穿衣指数",
"des": "建议着厚外套加毛衣等服装。年老体弱者宜着大衣、呢外套加羊毛衫。",
'xuhao': [
'a','b','c','d'
]
},
{
"title": "紫外线强度",
"zs": "中等",
"tipt": "紫外线强度指数",
"des": "属中等强度紫外线辐射天气,外出时建议涂擦SPF高于15、PA+的防晒护肤品,戴帽子、太阳镜。",
'xuhao': [
1, 2, 3, 4
]
}
]
}
]
}
这里要说一下,我们手动设定json不能用json.dumps处理,否则会报参数错误,即应该使用dict,api获取的则直接使用即可。
假设我们要获取key=‘xuhao‘的值
先不加参数试试
x = json_normalize(df)
print(x)
结果如下
发现深层嵌套的地方并没有按照想要的方式实现,就引出了json_normalize的第一个参数:record_path ,该参数传入一个列表,功能是目标层级:
x = json_normalize(df, record_path=['results','index','xuhao'],)
print(x)
结果如下
20211022更新:这里发现之前写的一个小bug 如果record_path直接定位到一个字典结构,即{},则会把里面的value全部拆开成单个字符,比如{‘name’,‘zhang’},会变成{‘name’,[‘z’,’‘h’,‘a’,‘n’,‘g’},所以record_path定位到的地方应该是一个列表里包含字典,即[{}],这样会自动识别出字典的key,
这里可以看到已经取出了我们需要的字段,列名为0 ,那么如果想要其他数据呢,则需要传入meta参数,同样传入列表,放入想展示的其他key
x = json_normalize(df, record_path=['results', 'index', 'xuhao'],
meta=['error', ['results', 'currentCity'], ['results', 'index', 'zs']])
print(x)
结果如下
如果有的json的某一个key不是稳定存在呢,比如这样
df = {
"error": 0,
"status": "success",
"results": [
{
"currentCity": "青岛",
"index": [
{
"title": "穿衣",
"zs": "较冷",
"tipt": "穿衣指数",
"des": "建议着厚外套加毛衣等服装。年老体弱者宜着大衣、呢外套加羊毛衫。",
'xuhao': [
'a', 'b', 'c', 'd'
]
},
{
"title": "紫外线强度",
"tipt": "紫外线强度指数",
"des": "属中等强度紫外线辐射天气,外出时建议涂擦SPF高于15、PA+的防晒护肤品,戴帽子、太阳镜。",
'xuhao': [
1, 2, 3, 4
]
}
]
}
]
}
我们对json进行了一点修改,删除了"title"为 "紫外线强度"对应的zs,那么会有什么结果呢,执行一下试试:
KeyError: "Try running with errors='ignore' as key 'zs' is not always present"
得到报错,尝试过执行但zs并不是一直存在,也给出了建议,即errors=‘ignore’ ,再试试:
x = json_normalize(df, record_path=['results', 'index', 'xuhao'],
meta=['error', ['results', 'currentCity'], ['results', 'index', 'zs']],
errors='ignore')
print(x)
结果如下:
会发现缺失的地方被NaN代替,但是也成功的转换成了dataframe,后续就可以进行正常的数据操作啦!!!