繁体   English   中英

使用Python处理非常丑陋的多行Json对象

[英]Prossing Very Ugly Multi-line Json Object with Python

好的,由于json严重击败了我,因此又是令人沮丧的一天。 如果这并不让人害怕,那么您就是我的新榜样。 很抱歉,我什至没有对此进行合理的尝试。 我有成千上万个具有以下结构的文件,以下甚至只是该文件中的一个示例,因此,请想象以下示例中的更多行,这些行需要格式化为csv格式才能加载到数据库和查询中。 是的,从技术上讲,每行都是json对象,但每行都具有可变结构,其中一些具有嵌套键,而其他则没有。 如果有人能让我朝着正确的方向前进,那我将不胜感激。 为了使事情变得更糟,文件的特定部分的行数永远不会保持一致,因此,当我尝试编写仅读取前20行的程序时,例如,因为至少我可以单独处理顶部,我遇到了一个号码不详的问题。

这是文件顶部的样子:

{
"key":[
{"key":["val"],"key":{"key":"val","key":"val", "key":{"key":"val", "key":"val"}, "key":{"key":"val"}, "key":"val"}, "key":"val"},
{"key":["val","val","val","val"],"key":{"key":"val","key":"val"},"key":"val"},
{"key":["val"],"key":{"key":"val","key":"val", "key":{"key":"val", "key":"val"}, "key":{"key":"val"}, "key":"val"}, "key":"val"},
{"key":["val","val","val","val"],"key":{"key":"val","key":"val"},"key":"val"}
],

这是文件底部的样子:

"key":[
{"key":"val","key":"val","key":["val", "val", "val", "val", "val", "val"]},
{"key":"val","key":"val","key":["val", "val", "val", "val", "val", "val"]},
{"key":"val","key":"val","key":["val", "val", "val", "val", "val", "val"]}
]
}

您给定的测试数据有点讨厌,因为:

  1. 您已经用“ key”替换了每个键,这使得json.load()返回单入口字典,其中包含了大部分数据;

  2. 它实际上与您的描述不符; 这是一个完全有效的单个json对象,而不是每隔几行就有一个json对象。

因此,我改为编写以下测试数据:

{"a": 35, "c": 16, "b": 98,
"e": 47, "d": 98, "f": 82}
{"a": 41, "c": 18, "b": 32, "e": 76, "d": 66, "f": 92}
{"a": 43, "c": 79, "b": 62, "e": 55,
"d": 86, "f": 61}
{"a": 47, "c": 49, "b": 87,
"e": 85, "d": 14, "f": 46}
{"a": 60, "c": 17, "b": 36, "e": 55, "d": 25, "f": 84}
{"a": 61, "c": 38, "b": 93, "e": 26, "d": 12, "f": 82}

然后我发现以下

import json

def iload_json(buff, decoder=None, _w=json.decoder.WHITESPACE.match):
    # found at http://www.benweaver.com/blog/decode-multiple-json-objects-in-python.html
    """Generate a sequence of top-level JSON values declared in the
    buffer.

    >>> list(iload_json('[1, 2] "a" { "c": 3 }'))
    [[1, 2], u'a', {u'c': 3}]
    """
    decoder = decoder or json._default_decoder
    idx = _w(buff, 0).end()
    end = len(buff)
    try:
        while idx != end:
            (val, idx) = decoder.raw_decode(buff, idx=idx)
            yield val
            idx = _w(buff, idx).end()
    except ValueError as exc:
        raise ValueError('%s (%r at position %d).' % (exc, buff[idx:], idx))

可以用作

import glob
from itertools import chain

def gen_json_from_file(fname):
    with open(fname) as inf:
        try:
            for obj in iload_json(inf.read()):
                yield obj
        except ValueError, e:
            print("Error parsing file '{}': {}".format(fname, e.message))

def gen_json_from_files(filespec):
    return chain(*(gen_json_from_file(fname) for fname in glob.glob(filespec)))

for obj in gen_json_from_files("*.json")):
    try:
        print(obj["a"])
    except KeyError:
        pass

哪一个(针对以上两次保存为“ a.json”和“ b.json”的测试数据运行)导致

35
41
43
47
60
61
35
41
43
47
60
61

如预期的那样。

因此,尽管给定示例,但解析起来并不困难,尽管比您描述的要容易一些。

如果“每一行是一个JSON对象”,您要做的就是将每行输入json解析器,并将结果对象收集在一个列表中:

import json
for filename in os.listitdir(<path_to_thousands_of_json_files>):
    data = [] 
    with open(filename) as jsonfile:
       for line in jsonfile:
           if not line.strip(): continue #avoid crash at empty lines and newline at end of file       data.append(json.loads(line.strip()))
    # do your CSV output processing here.

但是,在上面的示例中,每一行都不是一个完整的json文件-就像整个文件都是有效的json对象一样,就像规范一样,因此jsut会这样做:

import json
for filename in os.listitdir(<path_to_thousands_of_json_files>):
    data = json.load(open(filename))
    # do CSV output

应该为您完成工作。

现在,这是解析-如果您的问题仅与此有关,那么这些就足够了。 我想了解数据的含义并选择字段和标题以在每个CSV结果文件中输出将是一个更大的问题-但是它们,也许您可​​以使用直到解析工作完成,并通过更具体的示例发布更多问题您想要得到的东西;

请注意,要处理成千上万个文件,明智的做法是在Python中使用迭代器“模式”,以便可以将上述解析逻辑与处理数据和创建输出的部分分开,并具有单个JSON每次在内存中解析的文件:

import json

def get_json_data(path_to_files):
    for filename in os.listitdir(path_to_files):
        data = json.load(open(filename))
        yield data

def main():
    for data in get_json_data(<path_to_files>):
         # implement CSV logic here.

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM