Python:尝试对文件中的多个JSON对象进行反序列化,每个对象跨越多个但间隔一致的行数

hor*_*01d 24 python json

好吧,经过近一周的研究,我将给予一个机会.我有一个文本文件,如下所示(显示3个单独的json对象作为示例,但文件有50K这些):

{
"zipcode":"00544",
"current":{"canwc":null,"cig":7000,"class":"observation"},
"triggers":[178,30,176,103,179,112,21,20,48,7,50,40,57]
}
{
"zipcode":"00601",
"current":{"canwc":null,"cig":null,"class":"observation"},
"triggers":[12,23,34,28,100]
}
{
"zipcode":"00602",
"current":{"canwc":null,"cig":null,"class":"observation"},
"triggers":[13,85,43,101,38,31]
}
Run Code Online (Sandbox Code Playgroud)

我知道如何使用Python json库处理JSON对象,但是我对如何通过读取文件创建5万个不同的json对象提出了挑战.(也许我甚至没有正确地思考这个问题,但最终我需要反序列化并加载到数据库中)我已经尝试过itertools认为我需要一个生成器,所以我能够使用:

with open(file) as f:
    for line in itertools.islice(f, 0, 7): #since every 7 lines is a json object
        jfile = json.load(line)
Run Code Online (Sandbox Code Playgroud)

但是上面显然不会起作用,因为它不是将7行作为单个json对象读取,而且我也不确定如何迭代整个文件并加载单个json对象.

以下将给我一个我可以切片的列表:

list(open(file))[:7]
Run Code Online (Sandbox Code Playgroud)

任何帮助将非常感激.


非常接近我需要的东西,我认为只有一步之遥,但仍然在迭代中苦苦挣扎.这最终会让我对所有数据帧进行迭代打印输出,但是如何制作它以便我可以捕获一个巨大的数据帧,其中所有的部分基本上连接在一起?然后我可以将最终的数据帧导出到csv等.(还有更好的方法将此结果上传到数据库而不是先创建一个巨大的数据帧吗?)

def lines_per_n(f, n):
    for line in f:
        yield ''.join(chain([line], itertools.islice(f, n - 1)))

def flatten(jfile):
    for k, v in jfile.items():
        if isinstance(v, list):
            jfile[k] = ','.join(v)
        elif isinstance(v, dict):
            for kk, vv in v.items():
                jfile['%s' % (kk)] = vv
            del jfile[k]
            return jfile

with open('deadzips.json') as f:
    for chunk in lines_per_n(f, 7):
        try:
            jfile = json.loads(chunk)
            pd.DataFrame(flatten(jfile).items())
        except ValueError, e:
            pass
        else:
            pass
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 24

加载6个额外的行,并将字符串传递给json.loads():

with open(file) as f:
    for line in f:
        # slice the next 6 lines from the iterable, as a list.
        lines = [line] + list(itertools.islice(f, 6))
        jfile = json.loads(''.join(lines))

        # do something with jfile
Run Code Online (Sandbox Code Playgroud)

json.load()将不仅仅是文件中的下一个对象,而且islice(f, 0, 7)只读取前7行,而不是读取7行块中的文件.

您可以在生成器中以大小为N的块读取文件:

from itertools import islice, chain

def lines_per_n(f, n):
    for line in f:
        yield ''.join(chain([line], itertools.islice(f, n - 1)))
Run Code Online (Sandbox Code Playgroud)

然后用它来填充你的输入文件:

with open(file) as f:
    for chunk in lines_per_n(f, 7):
        jfile = json.loads(chunk)

        # do something with jfile
Run Code Online (Sandbox Code Playgroud)

或者,如果您的块变为长度可变,请阅读,直到您有解析的内容为止:

with open(file) as f:
    for line in f:
        while True:
            try:
                jfile = json.loads(line)
                break
            except ValueError:
                # Not yet a complete JSON value
                line += next(f)

        # do something with jfile
Run Code Online (Sandbox Code Playgroud)

  • 至于你的第二个解决方案,`JSONDecoder.raw_decode`基本上是为你做的. (4认同)

Jef*_*ker 9

如其他地方所述,一般的解决方案是将文件分片读取,将每个片段附加到最后,并尝试解析该新块.如果它不解析,继续,直到你得到的东西.一旦你有解析的东西,返回它,然后重新启动过程.冲洗 - 泡沫重复,直到数据用完为止.

这是一个简洁的生成器,它将执行此操作:

def load_json_multiple(segments):
    chunk = ""
    for segment in segments:
        chunk += segment
        try:
            yield json.loads(chunk)
            chunk = ""
        except ValueError:
            pass
Run Code Online (Sandbox Code Playgroud)

像这样使用它:

with open('foo.json') as f:
   for parsed_json in load_json_multiple(f):
      print parsed_json
Run Code Online (Sandbox Code Playgroud)

我希望这有帮助.