【问题标题】:JSON list/dictionary parsing from API从 API 解析 JSON 列表/字典
【发布时间】:2015-04-27 19:54:56
【问题描述】:

我开发了一个小型库,并希望让用户更轻松地从返回的 JSON 列表/字典中检索数据。我创建了使用requests 处理调用的函数。现在假设我调用这个函数并传入一些参数:

precip = precipitation_obs(stid='kfnl', start='201504261800', end='201504271200', units='precip|in')

这将返回以下 JSON:

{ 'STATION': [ { 'ELEVATION': '5016',
                 'ID': '192',
                 'LATITUDE': '40.45',
                 'LONGITUDE': '-105.01667',
                 'MNET_ID': '1',
                 'NAME': 'Fort Collins/Loveland, Fort Collins-Loveland '
                         'Municipal Airport',
                 'OBSERVATIONS': { 'count_1': 6,
                                   'ob_end_time_1': '2015-04-27T00:55:00Z',
                                   'ob_start_time_1': '2015-04-26T18:55:00Z',
                                   'total_precip_value_1': 0.13,
                                   'vids case4': ['39', '51', '40', '52']},
                 'STATE': 'CO',
                 'STATUS': 'ACTIVE',
                 'STID': 'KFNL',
                 'TIMEZONE': 'US/Mountain'}],
  'SUMMARY': { 'METADATA_RESPONSE_TIME': '5.22613525391 ms',
               'NUMBER_OF_OBJECTS': 1,
               'RESPONSE_CODE': 1,
               'RESPONSE_MESSAGE': 'OK',
               'TOTAL_TIME': '57.6429367065 ms'}}    

现在,我希望用户能够向下钻取字典,但 STATION 是一个列表,需要我执行以下操作:

output =  precip['STATION'][0]['OBSERVATIONS']['ob_start_time_1'] 
print(output)
# returns 2015-04-26T18:55:00Z

我必须包含 [0] 以避免:

TypeError: list indices must be integers, not str

这有什么问题吗?可以说,在其中添加 [0] 确实使事情变得更糟。甚至每次都必须指定 ['STATION'] 有点麻烦。我应该在这里使用 simpleJSON 模块来提供帮助吗?任何使这更容易的提示都会很棒,谢谢!

【问题讨论】:

  • 如果这是您的 API,那为什么不简化输出呢?是否只有一个站,然​​后不要使用列表。如果访问站元素很常见,并且只有一个站,请不要使用嵌套结构,而是将所有键移动到顶级对象等。
  • No simplejson 在这里没有帮助,因为它只是将 JSON 解析为相应的 Python 结构。
  • 反之,如果有可以多于一个站,你不能摆脱[0]这一步,因为如果有3个站,你需要能够访问#0、#1 和#2。您可以将该列表更改为由每个电台的 'STID' 值(因此它将是 precip['STATION']['KFNL']['OBSERVATIONS']['ob_start_time_1'])作为键的字典,但您无法摆脱它。

标签: python json python-3.x python-requests simplejson


【解决方案1】:

在其中添加 [0] 确实可以这么说。甚至每次都必须指定['STATION'] 有点麻烦。

所以只需将precip['STATION'][0] 存储在一个变量中:

>>> precip0 = precip['STATION'][0]

现在,你可以重复使用它了:

>>> precip0['OBSERVATIONS']['ob_start_time_1']
2015-04-26T18:55:00Z

如果您知道 API 将始终只返回一个站点,并且除了该站点的数据之外您永远不需要任何其他内容,则可以将其放入您的包装函数中:

def precipitation_obs(stid, start, end, units):
    # your existing code, which assigns something to result
    return result['STATION'][0]

如果您担心这里的“效率”,请不要担心。首先,这并没有复制任何东西,它只是对已经存在的同一个对象进行了另一个引用——它需要不到一微秒的时间,并且浪费了大约 8 个字节。事实上,它节省你的记忆,因为如果你不存储整个字典,只是子字典,Python 可以垃圾收集结构的其余部分。而且,更重要的是,在 (1) 您的代码正常工作并且 (2) 您知道这是一个瓶颈之前,这​​种微优化首先不值得担心。


我应该使用 simpleJSON 模块来提供帮助吗?

您为什么认为这会有所帮助?作为its readme says

simplejson 是 Python 2.6 和 Python 3.0 中包含的 json 库的外部维护开发版本,但保持与 Python 2.5 的向后兼容性。

换句话说,它要么是你已经在 stdlib 中获得的相同代码,要么是该代码的旧版本。

有时一个不同的库,比如ijson,可以提供帮助——例如,如果 JSON 结构太大以至于您无法将整个内容解析到内存中,或者太复杂以至于更容易用 SAX 风格倒置描述你想要的东西。但这与这里无关。

【讨论】:

  • 感谢您的详尽回复。我编写的第一段代码涉及 JSON/进行 API 调用。我很感激这个教训!
  • @jclark754:我的一位老同事曾经使用过一个 Firefox 扩展。它将 JSON 文档显示为一棵树,让您单击所需的任何位置,引导您通过从那里到顶部的路径,然后为您提供(JavaScript,不是 Python ......但它是相似的)代码用于索引和/或迭代步骤到达那里。不幸的是,我不记得它叫什么了,但你可能想寻找类似的东西。他发现即使作为 JS 奇才(虽然我没有),加速他的开发也很有帮助,而且作为一个新手,想象正在发生的事情可能更有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-04
  • 2021-09-25
相关资源
最近更新 更多