python - 如何打破具有嵌套对象的 JSON,以及如何创建一个可以传递多个项目的循环?
问题描述
我有 JSON 数据,我想将其转换为 CSV
我试过遵循这个如何将 JSON 转换为 CSV?但它仍然不起作用。
我知道我需要打破 JSON 中的嵌套对象以放入 CSV。
我担心的另一件事是我想要一个循环,其中多个项目(无论数量如何)可以通过代码,因为我的“ITEM”变量可能> 1
这是我的 JSON 样本
data_dict =
[{'count': 19804,
'next': {'limit': 1, 'offset': 1},
'previous': None,
'results': [{'company_name': 'Sunshine and Flowers',
'delivery_address': '34 olive beach house, #01-22, 612345',
'delivery_timeslot': {'bounds': '[)',
'items': [{'id': 21668,
'metadata': {},
'name': 'Loose hair flowers',
'quantity': 1,
'removed': None},
{'id': 21667,
'metadata': {},
'name': "Groom's Boutonniere",
'quantity': 1,
'removed': None},
{'id': 21666,
'metadata': {},
'name': 'Bridal Bouquet',
'quantity': 1,
'removed': None}],
'lower': '2019-12-06T10:00:00Z',
'upper': '2019-12-06T13:00:00Z'}}]}]
这是我迄今为止尝试过的
import csv
import json
dict_data = json.loads(dict_data)
f = csv.writer(open("test.csv", "wb+"))
for dict_data in dict_data:
f.writerow([dict_data["count"],
dict_data["next"]["limit"],
dict_data["next"]["offset"],
dict_data["results"]["company_name"],
dict_data["results"]["delivery_address"],
dict_data["results"]["delivery_timeslot"]["lower"]["'upper"]["'bounds"],
dict_data["results"]["items"]["id"]["name"]["'quantity"]["metadata"]["removed"]])
我收到的错误消息是这样的
'not {!r}'.format(s.__class__.__name__)) TypeError: the JSON object must be str, bytes or bytearray, not 'list'
解决方案
数据:
- 问题中显示的数据是
list
ofdicts
,不是格式正确的json
文件。 - 我创建了一个文件,
test.json
格式如下:
[{'count': 19804,...,'results': []},
{'count': 19805,...,'results': []},
{'count': 19806,...,'results': []}]`
- 数据与示例中给出的数据相同,重复 3 次。
读入数据ast.literal_eval
:
- 抽象语法树
- 标准库的一部分
import ast
with open("test.json", "r") as f:
data = ast.literal_eval(f.read())
用于pandas
解包嵌套dicts
:
import pandas as pd
from pandas.io.json import json_normalize
df = json_normalize(data,
record_path=['results', 'delivery_timeslot', 'items'],
meta=[['next'],
['count'],
['results', 'company_name'],
['results', 'delivery_timeslot', 'bounds'],
['results', 'delivery_timeslot', 'lower'],
['results', 'delivery_timeslot', 'upper']])
df[['next.limit', 'next.offset']] = df['next'].apply(pd.Series)
df.drop(columns=['next'], inplace=True)
数据框视图:
id name quantity removed metadata.lame metadata.horse count results.company_name results.delivery_timeslot.bounds results.delivery_timeslot.lower results.delivery_timeslot.upper next.limit next.offset
21668 Loose hair flowers 1 None Shit! Shit! 19804 Sunshine and Flowers [) 2019-12-06T10:00:00Z 2019-12-06T13:00:00Z 1 1
21667 Groom's Boutonniere 1 None This This 19804 Sunshine and Flowers [) 2019-12-06T10:00:00Z 2019-12-06T13:00:00Z 1 1
21666 Bridal Bouquet 1 None is is 19804 Sunshine and Flowers [) 2019-12-06T10:00:00Z 2019-12-06T13:00:00Z 1 1
21668 Loose hair flowers 1 None a a 19805 Sunshine and Flowers [) 2019-12-06T10:00:00Z 2019-12-06T13:00:00Z 1 1
21667 Groom's Boutonniere 1 None grassy grassy 19805 Sunshine and Flowers [) 2019-12-06T10:00:00Z 2019-12-06T13:00:00Z 1 1
21666 Bridal Bouquet 1 None knoll. knoll. 19805 Sunshine and Flowers [) 2019-12-06T10:00:00Z 2019-12-06T13:00:00Z 1 1
21668 Loose hair flowers 1 None NaN NaN 19806 Sunshine and Flowers [) 2019-12-06T10:00:00Z 2019-12-06T13:00:00Z 1 1
21667 Groom's Boutonniere 1 None NaN NaN 19806 Sunshine and Flowers [) 2019-12-06T10:00:00Z 2019-12-06T13:00:00Z 1 1
21666 Bridal Bouquet 1 None NaN NaN 19806 Sunshine and Flowers [) 2019-12-06T10:00:00Z 2019-12-06T13:00:00Z 1 1
- 根据需要重命名
columns
:df.rename(columns={'results.delivery_timeslot.lower': 'delivery_timeslot.lower'}, inplace=True)
将其保存到csv
:
df.to_csv('test.csv', index=False)