[英]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.