【问题标题】:JSON not getting saved correctlyJSON 未正确保存
【发布时间】:2019-03-07 17:51:35
【问题描述】:

所以我从 API 中提取数据,并且只想从 JSON 响应中保存特定的字典和列表。问题是,当我在循环中转储数据时,它会在文件中创建看起来非常奇怪的数据,而这些数据实际上并不是 JSON。

r=requests.get(url,headers=header)
result=r.json()
with open ('myfile.json','a+') as file:
    for log in result['logs']:
        hello=json.dump(log['log']['driver']['username'], file)
        hello=json.dump(log['log']['driver']['first_name'],file)
        hello=json.dump(log['log']['driver']['last_name'],file)
        for event in log['log']['events']:
            hello=json.dump(event['event']['id'],file)
            hello=json.dump(event['event']['start_time'],file)
            hello=json.dump(event['event']['type'],file)
            hello=json.dump(event['event']['location'],file)

这里的最终目标是将此数据转换为 CSV。我将它保存到 JSON 文件的唯一原因是我可以加载它并将其保存到 CSV 中。我的目标 API 端点是 Logs:

https://developer.keeptruckin.com/reference#get-logs

【问题讨论】:

  • 在循环中,根据需要构建对象 (dict),然后在最后一次,将 json.dump() 放入文件中。跨度>
  • 您希望 CSV 的每一行的 JSON 是什么样的?如果可能,请提供一个小样本。
  • 或者,您可以添加对 CSV 文件的行中应该包含的内容的描述,因为如果这是您的,我认为进行此中间 JSON 到 JSON 转换步骤没有太大优势最终目标。
  • @martineau 这是我在终端上运行带有 print 的 python 脚本时得到的示例:驱动程序 ID:benpa 名:演示 姓:一个 ID:1234566 开始时间:2019 -03-07T00:00:00-05:00 类型:驾驶位置:田纳西州诺克斯维尔 ID:1234565 开始时间:2019-03-07T01:20:47-05:00 类型:on_duty 位置:克利夫兰东北 9.2 英里, TN 司机 ID:laet 名字:Demo 姓氏:两个 ID:1234567 开始时间:2019-03-07T00:00:00-05:00 类型:驾驶位置:田纳西州查塔努加
  • 好的,我想我明白了。 CSV 文件的所有行通常都需要相同数量的字段,因此看起来驱动程序的名称必须在每个关联的事件行上重复。您可以通过将它们设置为空字符串来解决这个问题,除了同一驱动程序的一组它们的第一行之外。

标签: python json python-3.x api


【解决方案1】:

我认为@GBrandt 在创建有效的 JSON 输出方面有正确的想法,但正如我在评论中所说,我认为 JSON 到 JSON 的转换步骤并不是真正必要的——因为你可以创建您已经拥有的 JSON 中的 CSV 文件:

(修改为根据您的后续问题将start_time 拆分为两个单独的字段。)

result = r.json()

with open('myfile.csv', 'w', newline='') as csvfile:
    writer = csv.writer(csvfile, quoting=csv.QUOTE_ALL)
    for log in result['logs']:
        username = log['log']['driver']['username']
        first_name = log['log']['driver']['first_name']
        last_name = log['log']['driver']['last_name']

        for event in log['log']['events']:
            id = event['event']['id']
            start_time = event['event']['start_time']
            date, time = start_time.split('T')  # Split time into two fields.
            _type = event['event']['type']  # Avoid using name of built-in.
            location = event['event']['location']
            if not location:
                location = "N/A"
            writer.writerow(
                (username, first_name, last_name, id, date, time, _type, location))

【讨论】:

  • stardamore:请注意,quoting=csv.QUOTE_ALL 可能不是必需的——如果不使用它会使创建的 csv 文件稍微小一些。另请注意,我认为您不应该接受我的回答,因为它并没有真正解决您提出的有关保存 JSON 的问题(尽管我真的很欣赏这个手势)。
【解决方案2】:

看起来您只是以非结构化方式将单个 JSON 字符串转储到文件中。

json.dump 不会神奇地创建类似 JSON 字典的对象并将其保存到文件中。见:

json.dump(log['log']['driver']['username'], file)

它实际上所做的只是将驱动程序的用户名字符串化并将其直接转储到文件中,因此文件将只有一个字符串,而不是 JSON 对象(我猜这就是你想要的)。它 JSON,只是不是很有用。

你要找的是这个:

r=requests.get(url,headers=header)
result=r.json()
with open ('myfile.json','w+') as file:
    logs = []
    for log in result['logs']:
        logs.append({
            'username': log['log']['driver']['username'],
            'first_name': log['log']['driver']['first_name'],
            'last_name': log['log']['driver']['last_name'],
            # ...
            'events': [
                ({
                    'id': event['event']['id'],
                    'start_time': event['event']['start_time'],
                    # ...
                }) for event in log['log']['events']
            ]
        })
    json.dump(logs, file)

另外,我建议不要对 JSON 文件使用附加模式,.json 预计会保存一个 JSON 对象(就我而言)。

【讨论】:

  • 这是有道理的,但是当我检查 JSON Lint 上的 JSON 数据时,我似乎遇到了错误:错误:第 21 行的解析错误:...:25:45-05:00" } ]} { "username": "laet ---------^ 期待 'EOF', '}', ',', ']', got ' {'
  • @stardamore:这很奇怪,因为我刚刚尝试过的这个online JSON validator 表明创建的文件的内容 有效的(尽管我使用了自己的输入数据)。请注意,它在 JSON 中创建所谓的“数组”(类似于 Python 中的 list)。在外部数组的每个对象中还有一个嵌套的event 数组。
  • GBrandt:实际上,您的代码正在生成 JSON“objects”的 JSON“array”(请参阅​​format specification),这也是有效。
【解决方案3】:

下面的代码怎么样(示例 json 从文件加载,而不是通过 HTTP 调用以获取数据)。

https://developer.keeptruckin.com/reference#get-logs 获取的 JSON 示例

import json

with open('input.json', 'r') as f_in:
    data = json.load(f_in)

data_to_collect = []
logs = data['logs']
with open('output.json', 'w') as f_out:
    for log in logs:
        _log = log['log']
        data_to_collect.append({key: _log['driver'].get(key) for key in ['username', 'first_name', 'last_name']})
        data_to_collect[-1]['events'] = []
        for event in _log['events']:
            data_to_collect[-1]['events'].append(
                {key: event['event'].get(key) for key in ['id', 'start_time', 'type', 'location']})
    json.dump(data_to_collect, f_out)

输出文件

[
  {
    "username": "demo_driver",
    "first_name": "Demo",
    "last_name": "Driver",
    "events": [
      {
        "start_time": "2016-10-16T07:00:00Z",
        "type": "driving",
        "id": 221,
        "location": "Mobile, AL"
      },
      {
        "start_time": "2016-10-16T09:00:00Z",
        "type": "sleeper",
        "id": 474,
        "location": null
      },
      {
        "start_time": "2016-10-16T11:00:00Z",
        "type": "driving",
        "id": 475,
        "location": null
      }
    ]
  }
]

【讨论】:

    猜你喜欢
    • 2013-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-29
    • 1970-01-01
    • 1970-01-01
    • 2019-03-14
    相关资源
    最近更新 更多