Python ijson - parse error: trailing garbage // bz2.decompress()

Python ijson - parse error: trailing garbage // bz2.decompress()

我在用 ijson 解析 json 时遇到错误。

背景: 我有一系列(大约 1000 个)twitter 数据大文件,这些文件以“.bz2”格式压缩。我需要将文件中的元素放入 pd.DataFrame 以供进一步分析。我已经确定了我需要获取的密钥。我很谨慎地上传推特数据。

尝试: 我已经设法使用 bz2.decompress 和以下代码解压缩文件:

## Code in loop specific for decompressing and parsing - 

with open(file, 'rb') as source:
                # Decompress the file
                json_r = bz2.decompress(source.read())
                json_decom =  json_r.decode('utf-8') # decompresses one file at a time rather than a stream
                
                # Parse the JSON with ijson 
                parser = ijson.parse(json_decom)
                for prefix, event, value in parser:
                    # Print selected items as part of testing
                    if prefix=="created_at":
                        print(value)
                    if prefix=="text":
                        print(value)
                    if prefix=="user.id_str":
                        print(value)

这会产生以下错误:

IncompleteJSONError: parse error: trailing garbage
          estamp_ms":"1609466366680"}  {"created_at":"Fri Jan 01 01:59
                     (right here) ------^

两件事:

如有任何帮助,我们将不胜感激。

谢谢你,詹姆斯

直接回答你的两个问题:

  • 解压缩方法是正确的,因为它会产生 JSON 数据,然后您将这些数据提供给 ijson。正如您所指出的, ijson 可以与 strbytes 输入一起使用(尽管后者是首选);如果您给 ijson 一些非 JSON 输入,您将不会看到显示其中 JSON 数据的错误。

  • 这是一个非常常见的错误,描述为 in ijson's FAQ。这基本上意味着您的 JSON 文档有多个顶级值,这不是标准的 JSON,但 ijson 通过使用 multiple_values 选项支持(有关详细信息,请参阅文档)。

关于整个代码:虽然它工作正常,但可以改进:使用 ijson 的全部意义在于您可以避免在内存中加载完整的 JSON 内容。您发布的代码并没有利用它的优势:它首先打开 bz 压缩文件,将其作为一个整体读取,将 that 作为一个整体解压缩,(不必要地)解码 that作为一个整体,然后将解码后的数据作为输入给ijson。如果您的输入文件很小,并且解压缩的数据也很小,您不会看到任何影响,但如果您的文件很大,那么您肯定会开始注意到它。

一种更好的方法是通过所有操作流式传输数据,以便一切都以增量方式发生:解压缩、不解码和 JSON 解析。大致如下:

with bz2.BZ2File(filename, mode='r') as f:
    for prefix, event, value in ijson.parse(f):
        # ...

作为蛋糕上的樱桃,如果你想从中构建一个 DataFrame,你可以使用 DataFrame 的 data argument 直接用上面的结果构建 DataFrame。 data 可以是一个可迭代对象,因此您可以将上面的代码作为生成器并用作 data。同样,类似以下内容:

def json_input():
   with bz2.BZ2File(filename, mode='r') as f:
       for prefix, event, value in ijson.parse(f):
           # yield your results

df = pandas.DataFrame(data=json_input())