如何反序列化拆分的json数据

时间:2019-06-13 15:32:46

标签: python json deserialization

我通过服务器发送事件流式传输数据并得到500.000 datasets,但是我没有得到一个json,而是得到了它(500.000个数据集中的2个示例)(这看起来像是在gedit中打开它,所有问题标记为\“,所有新行均为\ n):

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

我的目标是将其保存到数据库中。我实际上以为我将其放入字典中,然后从此处创建一个pandas数据框,应该可以将其保存到数据库中。但这最终变得非常麻烦。我最终得到了这样的东西:

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获取数据,并且能够将它们存储为字节而不是字符串,如果有帮助的话,就可以了。

有什么建议吗?

2 个答案:

答案 0 :(得分:1)

与“替换”混为一谈,这当然是一条曲折的道路- 该语言确实内置了用于此类转义的解析器- 更简单的方法是通过eval调用传递包含JSON的字符串。但是,很少需要评估,并且在大多数情况下应避免为“不雅观”(如果不是绝对不安全的话)(但是不安全实际上仅适用于您无法控制输入数据的情况,甚至是ast.literal_eval而不是普通eval可以缓解这种情况)。无论如何,格式还有其他问题,它们将阻止eval完全工作-例如,最外面的data:的引号丢失。

如果您的文件内容实际上是随机的,那么

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

它有两个问题:最外面的data的“引号不足”和 内部数据的“过度修饰”。

在交互式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反序列化器轻松处理此问题:仅当文件未如我们所展示的那样损坏时-不可能的标准序列化程序才能知道如何处理这样的特定开箱即用的数据格式。但是,如果您实际上是另一种语言/技术的熟练者,则可以求助于从中断的输入到正确编码的文件编写一个转换器,并将其用作中间步骤。

答案 1 :(得分:0)

我不确定我是否正确理解了正确获取字符串的格式,因此,如果我在这里输入错误,请纠正我:

a

您的第一行似乎删除了第一个和最后一个字符,我看不到。您还要在这里剥离其他字符吗?

下面的两个子字符串替换似乎无效,因为子字符串不存在于初始字符串中(如果我一开始就正确地找到了它)。

最后,在最后一行中,您用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 或对该字符串进行任何操作了。