簡體   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