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
Ответы
Ответ 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
Надеюсь, это поможет.