从不完整的 HTTP JSON 响应中完成一个 json 字符串

有时我会从 json api 下载数据,它中途切断,通常是由于网络超时或其他一些问题。但是,在这种情况下,我希望能够读取可用数据。下面是一个例子:


{

    "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 对象(如上述)执行上述操作?


三国纷争
浏览 195回答 2
2回答

慕尼黑的夜晚无繁华

为这个任务编写解析器的想法在智力上真的很有趣,但我强烈警告你不要遵循这种方法。根本问题是,当网络请求失败时,您将进入未定义行为的领域。你绝对不能保证你的结果输出会是什么,所以你可能不应该尝试修改一个。这两种可能性要么是您的输入不完整但部分可理解,要么是完全不可理解。增加的复杂性与失败的网络请求的未定义性质相结合意味着您可能不应该尝试定义它。以TCP/IP 协议如何处理类似问题为例。对于网络,经常会出现数据包丢失,这意味着部分数据无法完全传输。引用维基百科的话说,TCP“检测数据包丢失并执行重传以确保可靠的消息传递”。我强烈建议采用类似的方法。要么重新获取数据,要么简单地将错误视为福音,并对错误状态进行处理。

慕码人2483693

这是我这样做的方式,构建一堆}和]字符来尝试“完成”。它有点冗长,可以清理,但它适用于我尝试过的一些字符串输入: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' stackunfinished = []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 jsondata = Nonewhile 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
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python