[英]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"]}
]
}
您给定的测试数据有点讨厌,因为:
您已经用“ key”替换了每个键,这使得json.load()返回单入口字典,其中包含了大部分数据;
它实际上与您的描述不符; 这是一个完全有效的单个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.