Python 从不完整的HTTP json响应中完成json字符串
有时我会从json api下载数据,中途中断,通常是由于网络超时或其他一些问题。但是,在这种情况下,我希望能够读取可用的数据。以下是一个例子:Python 从不完整的HTTP json响应中完成json字符串,python,json,python-3.x,api,http,Python,Json,Python 3.x,Api,Http,有时我会从json api下载数据,中途中断,通常是由于网络超时或其他一些问题。但是,在这种情况下,我希望能够读取可用的数据。以下是一个例子: { "response": 200, "message": None, "params": [] "body": { "timestamp": 1546033192, "_d": [ {"id": "FMfcgxwBTsWRDsWDqgqRtZlLMdpCpT
{
"response": 200,
"message": None,
"params": []
"body": {
"timestamp": 1546033192,
"_d": [
{"id": "FMfcgxwBTsWRDsWDqgqRtZlLMdpCpTDz"},
{"id": "FMfcgxwBTkFSKqRrcKzMFvLCjDSSbrJH"},
{"id": "Fmfgo9
我希望能够“完成字符串”,以便能够将不完整的响应解析为json。例如:
s = '''
{
"response": 200,
"message": null,
"params": [],
"body": {
"timestamp": 1546033192,
"_d": [
{"id": "FMfcgxwBTsWRDsWDqgqRtZlLMdpCpTDz"},
{"id": "FMfcgxwBTkFSKqRrcKzMFvLCjDSSbrJH"}
]
}
}'''
json.loads(s)
{'response': 200, 'message': None, 'params': [], 'body': {'timestamp': 1546033192, '_d': [{'id': 'FMfcgxwBTsWRDsWDqgqRtZlLMdpCpTDz'}, {'id': 'FMfcgxwBTkFSKqRrcKzMFvLCjDSSbrJH'}]}}
我怎样才能用一个任意构造的json对象(如上所述)完成上述操作?我就是这样做的,构建一个由
}
和]
字符组成的堆栈,以尝试“结束”。它有点冗长,可以清理,但它可以在我尝试过的几个字符串输入上工作:
s='''{
"response": 200,
"message": null,
"params": [],
"body": {
"timestamp": 1546033192,
"_d": [
{"id": "FMfcgxwBTsWRDsWDqgqRtZlLMdpCpTDz"},
{"id": "FMfcgxwBTkFSKqRrcKzMFvLCjDSSbrJH"},
{"id": "Fmfgo9'''
>>> f.complete_json_structure(s)
{'response': 200, 'message': None, 'params': [], 'body': {'timestamp': 1546033192, '_d': [{'id': 'FMfcgxwBTsWRDsWDqgqRtZlLMdpCpTDz'}, {'id': 'FMfcgxwBTkFSKqRrcKzMFvLCjDSSbrJH'}]}}
代码如下:
# Build the 'unfinished character' stack
unfinished = []
for char in file_data:
if char in ['{', '[']:
unfinished.append(char)
elif char in ['}', ']']:
inverse_char = '{' if char == '}' else '['
# Remove the last one
unfinished.reverse()
unfinished.remove(inverse_char)
unfinished.reverse()
# Build the 'closing occurrence string'
unfinished.reverse()
unfinished = ['}' if (char == '{') else ']' for char in unfinished]
unfinished_str = ''.join(unfinished)
# Do a while loop to try and parse the json
data = None
while True:
if not json_string:
raise FileParserError("Could not parse the JSON file or infer its format.")
if json_string[-1] in ('}', ']'):
try:
data = json.loads(json_string + unfinished_str)
except json.decoder.JSONDecodeError:
# do it a second time as a sort of hack to fix the "trailing comma issue" (or could do a remove last comma, but that gets tricky)
try:
data = json.loads(json_string + unfinished_str[1:])
except json.decoder.JSONDecodeError:
pass
if data is not None:
break
if json_string[-1] == unfinished_str[0]:
unfinished_str = unfinished_str[1:]
json_string = json_string[:-1].strip().rstrip(',')
return data
我就是这样做的,构建一个由
}
和]
字符组成的堆栈来尝试“结束”。它有点冗长,可以清理,但它可以在我尝试过的几个字符串输入上工作:
s='''{
"response": 200,
"message": null,
"params": [],
"body": {
"timestamp": 1546033192,
"_d": [
{"id": "FMfcgxwBTsWRDsWDqgqRtZlLMdpCpTDz"},
{"id": "FMfcgxwBTkFSKqRrcKzMFvLCjDSSbrJH"},
{"id": "Fmfgo9'''
>>> f.complete_json_structure(s)
{'response': 200, 'message': None, 'params': [], 'body': {'timestamp': 1546033192, '_d': [{'id': 'FMfcgxwBTsWRDsWDqgqRtZlLMdpCpTDz'}, {'id': 'FMfcgxwBTkFSKqRrcKzMFvLCjDSSbrJH'}]}}
代码如下:
# Build the 'unfinished character' stack
unfinished = []
for char in file_data:
if char in ['{', '[']:
unfinished.append(char)
elif char in ['}', ']']:
inverse_char = '{' if char == '}' else '['
# Remove the last one
unfinished.reverse()
unfinished.remove(inverse_char)
unfinished.reverse()
# Build the 'closing occurrence string'
unfinished.reverse()
unfinished = ['}' if (char == '{') else ']' for char in unfinished]
unfinished_str = ''.join(unfinished)
# Do a while loop to try and parse the json
data = None
while True:
if not json_string:
raise FileParserError("Could not parse the JSON file or infer its format.")
if json_string[-1] in ('}', ']'):
try:
data = json.loads(json_string + unfinished_str)
except json.decoder.JSONDecodeError:
# do it a second time as a sort of hack to fix the "trailing comma issue" (or could do a remove last comma, but that gets tricky)
try:
data = json.loads(json_string + unfinished_str[1:])
except json.decoder.JSONDecodeError:
pass
if data is not None:
break
if json_string[-1] == unfinished_str[0]:
unfinished_str = unfinished_str[1:]
json_string = json_string[:-1].strip().rstrip(',')
return data
为这项任务编写解析器的想法在智力上确实很有趣,但我强烈警告您不要采用这种方法 基本问题是,当网络请求失败时,您将进入未定义行为的领域。你绝对不能保证你的结果会是什么,所以你可能不应该试图欺骗一个 这两种可能性要么是您的输入不完整但部分可理解,要么是完全不可理解。增加的复杂性加上失败的网络请求的未定义性质意味着您可能无论如何都不应该尝试定义它 举个例子,政府如何处理类似的问题。在网络中,通常会出现错误,这意味着部分数据无法完全传输。引用维基百科的话,TCP“检测数据包丢失并执行重传以确保可靠的消息传递”
我强烈建议采取类似的做法。要么重新获取数据,要么简单地将错误当作福音,并对错误状态进行处理。为这项任务编写解析器的想法在智力上非常有趣,但我强烈警告您不要采用这种方法 基本问题是,当网络请求失败时,您将进入未定义行为的领域。你绝对不能保证你的结果会是什么,所以你可能不应该试图欺骗一个 这两种可能性要么是您的输入不完整但部分可理解,要么是完全不可理解。增加的复杂性加上失败的网络请求的未定义性质意味着您可能无论如何都不应该尝试定义它 举个例子,政府如何处理类似的问题。在网络中,通常会出现错误,这意味着部分数据无法完全传输。引用维基百科的话,TCP“检测数据包丢失并执行重传以确保可靠的消息传递”
我强烈建议采取类似的做法。要么重新获取数据,要么简单地将错误当作福音,并对错误状态进行处理。非常确定您不能,它可能是任意结构。猜测结构的结尾可能没有帮助。@roganjosh我们可以数一数“未完成的”
}
s和]
s的数量,然后尝试将其添加到(可能还有未完成的引号吗?您需要从头开始编写自己的JSON解析器。在这种情况下,在数据中断时,您应该能够返回到解析树并关闭任何“打开的”数组、字典等。你是如何得到部分响应的?如果出现网络错误,我希望库抛出异常而不返回任何内容。@larsks你看到我在下面编写的基本解析器有什么突出的问题吗?你肯定看不到,它可能是任意结构。猜测结构的结尾是p很可能没有帮助。@roganjosh我们能数一数“未完成的”}
s和]
s的数量,并尝试通过将其添加到(可能还有未完成的引号吗?您需要从头开始编写自己的JSON解析器。在这种情况下,在数据中断时,您应该能够返回到解析树并关闭任何“打开的”数组、字典等。您是如何得到部分响应的?如果出现网络错误,我希望库抛出异常而不返回任何内容。@larsks您看到我在下面编写的基本解析器有什么突出的问题吗?我同意。我只是使用“失败的http请求”作为一个例子——我们使用指数退避和大约1000行代码来处理一些重试等。上面的问题更多的是关于“如何任意解析不完整的json”,我只是使用不完整的http响应作为一个例子(它也可以分块加载一个文件,等等)明白了。这是一个非常有趣的问题!我同意。我只是以“失败的http请求”为例——我们使用指数退避和大约1000行代码来处理一些重试等。上面的问题更多的是关于“如何任意解析不完整的json”,我只是以一个不完整的http响应为例(它也可能是分块加载一个文件,等等),明白了,这是一个非常有趣的问题!