【问题标题】:How to deserialize splitted json data如何反序列化拆分的 json 数据
【发布时间】:2019-06-13 15:32:46
【问题描述】:

我通过服务器发送事件流式传输数据并得到500.000 datasets,但我没有得到一个json,而是得到了这个(500.000 个数据集中的2个的例子)(这是在gedit中打开它的样子,所有问号都是\" 并且所有新行都是 \n):

data:{\"data\":[\"Kendrick\",\"Lamar\"]}\n\ndata:{\"data\":[\"David\",\"Bowie\"]}\n\n
... -

我的目标是将其放入数据库。我实际上以为我将其放入字典中,然后从这里创建一个熊猫数据框,我应该能够将其放入数据库中。但这最终变得非常麻烦。我最终得到了这样的结果:

c1 = data_json[1:-1]
c2 = c1.replace('{data:{', '{\"data\":{')
c3 = c2.replace('}data:{', ', ')
c4 = '{' + c3 + '}' 

但即使在这里我也有一些问题,因为我必须为新行添加 /n/n。但是一旦我将c3 更改为c2.replace('}\n\ndata:{', ', '),我就会得到Process finished with exit code 137 (interrupted by signal 9: SIGKILL)。来自.NET,我可以使用反序列化器轻松处理这个问题,我想知道是否有类似的方法来反序列化数据。 我通过 sseclient 获取数据,并且能够将它们存储为字节而不是字符串,如果这有帮助,仅供参考。

有什么建议吗?

【问题讨论】:

    标签: python json deserialization


    【解决方案1】:

    玩弄替换当然是一条复杂的道路 - 该语言确实具有内置的这种转义的解析器 - 更简单的方法是通过 eval 调用传递包含 JSON 的字符串。但是很少需要 eval 并且在大多数情况下应该避免使用 eval ,因为它“不优雅”——如果不是完全不安全的话(但不安全实际上只适用于你无法控制输入数据的情况——甚至它们,ast.literal_eval 而不是普通的@ 987654323@ 可以减轻这种情况)。无论如何,格式还有其他问题会阻止 eval 直接工作 - 例如,最外面的data: 缺少引号。

    如果您的文件内容实际上是:

    data:{\"data\":[\"Kendrick\",\"Lamar\"]}\n\ndata:{\"data\":[\"David\",\"Bowie\"]}\n\n
    

    它有两个问题:“引用不足”最外面的 data 和 内部数据的“over-scaping”。

    在交互式 Python 会话中,使用“原始字符串”标记我可以输入您的示例行,因为它将从文件中读取:

    In [263]: a = r"""data:{\"data\":[\"Kendrick\",\"Lamar\"]}\n\ndata:{\"data\":[\"David\",\"Bowie\"]}\n\n"""                                             
    
    In [264]: print(a)                                                                                                                                     
    data:{\"data\":[\"Kendrick\",\"Lamar\"]}\n\ndata:{\"data\":[\"David\",\"Bowie\"]}\n\n
    

    所以,要删除一级反斜杠 - Python 有一个“unicode_escape”文本编码,但它只适用于字节对象。然后我们求助于“latin1”编码,因为它提供了“a”中的 unicode 文字到字节的逐字节转换,然后应用 unicode_escape 来删除“\”:

    In [266]: b = a.encode("latin1").decode("unicode_escape")  
    
    In [267]: print(b, "\n", repr(b))                                                                                                                      
    data:{"data":["Kendrick","Lamar"]}
    
    data:{"data":["David","Bowie"]}
    
    
     'data:{"data":["Kendrick","Lamar"]}\n\ndata:{"data":["David","Bowie"]}\n\n'
    

    现在很容易解析: 我们在 "\n\n" 处拆分结果字符串,并有一个包含一条记录的列表 (你称之为“数据集”的那些)每个元素。然后我们求助于字符串 操作以摆脱起始"data:",最后,json.load 可以处理剩余部分。

    所以:

    import json
    
    raw_data = open("mystrangefile.pseudo_json").read()
    data = data.encode("latin1").decode("unicode_escape")
    records = [json.loads(record.split(":", 1)[-1]) for record in data.split("\n\n")]
    

    “记录”现在应该包含表现良好的 Python 对象字典,您可以放入数据库。 (除非 Pandas 可以提供列到数据库的自动映射,否则这似乎是一个不需要的步骤 - 一个原始的 connection.executemany(""" INSERT ...""", records) 具有适当的开放数据库连接就足够了。

    另外,在旁注中,您提到您可以使用 .NET 反序列化程序轻松处理此问题:前提是您的文件没有像您向我们展示的那样损坏 - 没有可能的标准序列化程序知道如何处理这样一个特定的开箱即用的数据格式。但是,如果您实际上更精通另一种语言/技术来做到这一点,您可以只写一个转换器,从损坏的输入到正确编码的文件,并将其用作中间步骤。

    【讨论】:

      【解决方案2】:

      我不完全确定我是否理解了你正确获取字符串的格式,所以如果我在这里错了,请纠正我:

      data_json = 'data:{\\"data\\":[\\"Kendrick\\",\\"Lamar\\"]}\\n\\ndata:{\\"data\\":[\\"David\\",\\"Bowie\\"]}\\n\\n'

      您的第一行似乎去掉了第一个和最后一个字符,我没有看到。您是否在此处删除了任何其他字符?

      以下两个子字符串替换似乎没有效果,因为初始字符串中不存在子字符串(如果我一开始就正确理解的话)。

      最后在最后一行你用{} 包装你的结果,这对于json 中的列表是不正确的。应该是[...]

      不过,我真的不知道为什么你会在这里得到一个 SIGKILL。它不会为我抛出任何错误,它只是没有做你想做的事。也许您的所有 500k 示例的内存都用完了?

      但是,这将是一个可行的解决方案(同样,鉴于我正确获取了初始字符串):

      c1 = data_json.replace('\\n\\n', '')  # removing escaped newlines
      c2 = c1.replace('data:', ',') # replacing the additional 'data:' with json delimiter ','
      c3 = c2.replace('\\', '') # removing artificial escapes
      c4 = c3[1:-1] # removing leading ',' (introduced in c2) and trailing newline
      c5 = '[' + c4 + ']' # wrapping as list
      

      现在您应该可以json.loads(c5) 或任何您需要对该字符串执行的操作。

      【讨论】:

        猜你喜欢
        • 2013-08-17
        • 2016-05-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-27
        • 1970-01-01
        • 2018-04-22
        相关资源
        最近更新 更多