[英]How can I extract a single value from a JSON response?
我编写了一些代码来从 web API 获取数据。 我能够解析来自 API 的 JSON 数据,但我得到的结果看起来相当复杂。 这是一个例子:
>>> my_json
{'name': 'ns1:timeSeriesResponseType', 'declaredType': 'org.cuahsi.waterml.TimeSeriesResponseType', 'scope': 'javax.xml.bind.JAXBElement$GlobalScope', 'value': {'queryInfo': {'creationTime': 1349724919000, 'queryURL': 'http://waterservices.usgs.gov/nwis/iv/', 'criteria': {'locationParam': '[ALL:103232434]', 'variableParam': '[00060, 00065]'}, 'note': [{'value': '[ALL:103232434]', 'title': 'filter:sites'}, {'value': '[mode=LATEST, modifiedSince=null]', 'title': 'filter:timeRange'}, {'value': 'sdas01', 'title': 'server'}]}}, 'nil': False, 'globalScope': True, 'typeSubstituted': False}
通过这些数据,我可以看到我想要的具体数据:标记为'creationTime'
的1349724919000
值。
如何编写直接获取此值的代码?
我不需要任何搜索逻辑来找到这个值。 当我查看响应时,我可以看到我需要什么; 我只需要知道如何以硬编码的方式将其转换为特定代码以提取特定值。 我阅读了一些教程,所以我知道我需要使用[]
来访问嵌套列表和字典的元素; 但我无法弄清楚它是如何处理复杂案例的。
更一般地说,我怎样才能弄清楚数据的“路径”是什么,并为它编写代码?
作为参考,让我们看看原始的 JSON 是什么样子的,格式很漂亮:
>>> print(json.dumps(my_json, indent=4))
{
"name": "ns1:timeSeriesResponseType",
"declaredType": "org.cuahsi.waterml.TimeSeriesResponseType",
"scope": "javax.xml.bind.JAXBElement$GlobalScope",
"value": {
"queryInfo": {
"creationTime": 1349724919000,
"queryURL": "http://waterservices.usgs.gov/nwis/iv/",
"criteria": {
"locationParam": "[ALL:103232434]",
"variableParam": "[00060, 00065]"
},
"note": [
{
"value": "[ALL:103232434]",
"title": "filter:sites"
},
{
"value": "[mode=LATEST, modifiedSince=null]",
"title": "filter:timeRange"
},
{
"value": "sdas01",
"title": "server"
}
]
}
},
"nil": false,
"globalScope": true,
"typeSubstituted": false
}
这让我们更清楚地看到数据的结构。
在具体情况下,首先我们要查看我们解析的数据中'value'
键下的对应值。 那是另一个命令; 我们可以以相同的方式访问其'queryInfo'
键的值,同样可以从那里访问'creationTime'
。
为了获得所需的值,我们只需将这些访问一个接一个地放置:
my_json['value']['queryInfo']['creationTime'] # 1349724919000
我只需要知道如何以硬编码的方式将其转换为特定代码以提取特定值。
如果再次访问 API,新数据可能与代码的预期不符。 您可能会发现添加一些错误处理很有用。 例如,使用.get()
访问数据中的字典,而不是索引:
name = my_json.get('name') # will return None if 'name' doesn't exist
另一种方法是显式测试密钥:
if 'name' in resp_dict:
name = resp_dict['name']
else:
pass
但是,如果需要进一步访问,这些方法可能会失败。 None
的占位符结果不是字典或列表,因此尝试以这种方式访问它会再次失败(使用TypeError
)。 由于“简单胜于复杂”和“请求宽恕比请求许可更容易”,直接的解决方案是使用异常处理:
try:
creation_time = my_json['value']['queryInfo']['creationTime']
except (TypeError, KeyError):
print("could not read the creation time!")
# or substitute a placeholder, or raise a new exception, etc.
下面是从简单的 JSON 数据加载单个值并来回转换为 JSON 的示例:
import json
# load the data into an element
data={"test1": "1", "test2": "2", "test3": "3"}
# dumps the json object into an element
json_str = json.dumps(data)
# load the json to a string
resp = json.loads(json_str)
# print the resp
print(resp)
# extract an element in the response
print(resp['test1'])
尝试这个。
在这里,我只从COVID API(一个 JSON 数组)中获取状态码。
import requests
r = requests.get('https://api.covid19india.org/data.json')
x = r.json()['statewise']
for i in x:
print(i['statecode'])
尝试这个:
from functools import reduce
import re
def deep_get_imps(data, key: str):
split_keys = re.split("[\\[\\]]", key)
out_data = data
for split_key in split_keys:
if split_key == "":
return out_data
elif isinstance(out_data, dict):
out_data = out_data.get(split_key)
elif isinstance(out_data, list):
try:
sub = int(split_key)
except ValueError:
return None
else:
length = len(out_data)
out_data = out_data[sub] if -length <= sub < length else None
else:
return None
return out_data
def deep_get(dictionary, keys):
return reduce(deep_get_imps, keys.split("."), dictionary)
然后你可以像下面这样使用它:
res = {
"status": 200,
"info": {
"name": "Test",
"date": "2021-06-12"
},
"result": [{
"name": "test1",
"value": 2.5
}, {
"name": "test2",
"value": 1.9
},{
"name": "test1",
"value": 3.1
}]
}
>>> deep_get(res, "info")
{'name': 'Test', 'date': '2021-06-12'}
>>> deep_get(res, "info.date")
'2021-06-12'
>>> deep_get(res, "result")
[{'name': 'test1', 'value': 2.5}, {'name': 'test2', 'value': 1.9}, {'name': 'test1', 'value': 3.1}]
>>> deep_get(res, "result[2]")
{'name': 'test1', 'value': 3.1}
>>> deep_get(res, "result[-1]")
{'name': 'test1', 'value': 3.1}
>>> deep_get(res, "result[2].name")
'test1'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.