Загрузка и анализ файла JSON с несколькими объектами JSON в Python
Я пытаюсь загрузить и проанализировать файл JSON в Python. Но я застрял, пытаясь загрузить файл:
import json
json_data = open('file')
data = json.load(json_data)
Урожайность:
ValueError: Extra data: line 2 column 1 - line 225116 column 1 (char 232 - 160128774)
Я посмотрел на 18,2. json
- Кодер и декодер JSON в документации по Python, но читать эту ужасно выглядящую документацию довольно обескураживающе.
7 ответов
У вас есть текстовый файл в формате JSON Lines. Вам нужно проанализировать ваш файл построчно:
import json
data = []
with open('file') as f:
for line in f:
data.append(json.loads(line))
Каждая строка содержит допустимый JSON, но в целом это недопустимое значение JSON, поскольку нет списка верхнего уровня или определения объекта.
Обратите внимание, что, поскольку файл содержит JSON на строку, вы избавлены от головной боли при попытке проанализировать все это за один раз или выяснить потоковый анализатор JSON. Теперь вы можете обрабатывать каждую строку отдельно, а затем переходить к следующей, сохраняя при этом память. Вы, вероятно, не хотите добавлять каждый результат в один список, а затем обрабатывать все, если ваш файл действительно большой.
Если у вас есть файл, содержащий отдельные объекты JSON с разделителями между ними, используйте Как использовать модуль 'json' для чтения в одном объекте JSON одновременно? анализировать отдельные объекты с использованием буферизованного метода.
Если вы используете
pandas
и вам будет интересно загрузить
json
файл в качестве фрейма данных, вы можете использовать:
import pandas as pd
df = pd.read_json('file.json', lines=True)
А чтобы преобразовать его в массив json, вы можете использовать:
df.to_json('new_file.json')
Для тех, кто наткнулся на этот вопрос: питон jsonlines
библиотека (намного моложе этого вопроса) элегантно. обрабатывает файлы с одним документом json на строку. см. https://jsonlines.readthedocs.io/
Это плохо отформатировано. У вас есть один объект JSON на строку, но они не содержатся в более крупной структуре данных (то есть в массиве). Вам нужно либо переформатировать его, чтобы оно начиналось с [
и заканчивается ]
с запятой в конце каждой строки или разбирайте ее построчно как отдельные словари.
Точно так же, как ответ Мартейна Питерса, но, возможно, немного более питонический и, прежде всего, обеспечивающий потоковую передачу данных (см. вторую часть ответа):
import json
with open(filepath, "r") as f:
return list(map(json.loads, f))
The map(function, iterable)
функция возвращает итератор, который применяетсяfunction
к каждому предметуiterable
, что дает результаты (см. документ Map() Python).
Иlist
преобразует этот итератор в... список :)
Но вы можете представить, что вместо этого напрямую используете итератор, возвращаемый картой: он перебирает каждую из ваших строк json. Обратите внимание, что в этом случае вам нужно сделать это вwith open(filepath, "r") as f
контекст: в этом сила этого подхода: строки json не полностью загружаются в список, они передаются в потоковом режиме: функция карты считывает каждую строку файла, когдаnext(iterator)
вызываетсяfor loop
.
Это дало бы:
import json
with open(file path, "r") as f:
iterator_over_lines = map(json.loads, f)
# just as you would do with a list but here the file is streamed
for jsonline in iterator_over_lines:
# do something for each line
# the function mapped, json.loads is only call on each iteration
# that's why the file must stay opened
# You can try to call yourself the next function used by the for loop:
next_jsonline = next(iterator_over_lines)
nextnext_jsonline = next(iterator_over_lines)
И мне нечего добавить к ответу Мартейна для объяснения того, что такое jsonl (построчный файл json) и зачем его использовать!
теперь вы можете сделать это в одной строке, которая более питонична:
import json
data = [json.loads(line) for line in open('file', 'r').read().split('\n')]
Дополнение к ответу @arunppsg, но с многопроцессорной обработкой для работы с большим количеством файлов в каталоге.
import numpy as np
import pandas as pd
import json
import os
import multiprocessing as mp
import time
directory = 'your_directory'
def read_json(json_files):
df = pd.DataFrame()
for j in json_files:
with open(os.path.join(directory, j)) as f:
df = df.append(pd.read_json(f, lines=True)) # if there's multiple lines in the json file, flag lines to true, false otherwise.
return df
def parallelize_json(json_files, func):
json_files_split = np.array_split(json_files, 10)
pool = mp.Pool(mp.cpu_count())
df = pd.concat(pool.map(func, json_files_split))
pool.close()
pool.join()
return df
# start the timer
start = time.time()
# read all json files in parallel
df = parallelize_json(json_files, read_json)
# end the timer
end = time.time()
# print the time taken to read all json files
print(end - start)