Подтвердить что ты не робот

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]
}

Я знаю, как работать с объектами JSON с использованием библиотеки json Python, но у меня есть проблема с тем, как создавать 50 тысяч различных 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)

Но выше, очевидно, не будет работать, так как он не читает 7 строк как один объект json, и я также не уверен, как потом перебрать весь файл и загрузить отдельные json-объекты.

Следующее предоставит мне список, который я могу нарезать:

list(open(file))[:7]

Любая помощь будет действительно оценена.


Очень близко к тому, что мне нужно, и я думаю буквально в одном шаге, но все еще немного борюсь с итерацией. Это, наконец, даст мне итеративную распечатку всех фреймов данных, но как я могу сделать это так, чтобы я мог захватить один гигантский фреймворк со всеми кусками, по существу связанными? Я мог бы затем экспортировать этот окончательный файл данных в 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
4b9b3361

Ответ 1

Вместо этого загрузите 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

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)))

затем используйте это, чтобы разбить ваш входной файл:

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

        # do something with jfile

В качестве альтернативы, если ваши блоки имеют переменную длину, прочитайте, пока не получите что-то, что анализирует:

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

Ответ 2

Как указано в другом месте, общее решение состоит в том, чтобы прочитать файл по частям, добавить каждую часть до последней и попытаться проанализировать этот новый фрагмент. Если он не разбирается, продолжайте, пока не получите что-то, что делает. Когда у вас есть что-то, что анализирует, верните его и перезапустите процесс. Промойте-пена-повторите, пока не закончите данные.

Вот краткий генератор, который сделает это:

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

Используйте его следующим образом:

with open('foo.json') as f:
   for parsed_json in load_json_multiple(f):
      print parsed_json

Надеюсь, это поможет.