Ładowanie i analizowanie pliku JSON z wieloma obiektami JSON

101

Próbuję załadować i przeanalizować plik JSON w Pythonie . Ale utknąłem próbując załadować plik:

import json
json_data = open('file')
data = json.load(json_data)

Plony:

ValueError: Extra data: line 2 column 1 - line 225116 column 1 (char 232 - 160128774)

Spojrzałem na 18,2. json- Koder i dekoder JSON w dokumentacji Pythona, ale czytanie tej okropnie wyglądającej dokumentacji jest dość zniechęcające.

Kilka pierwszych wierszy (zanonimizowanych za pomocą losowych wpisów):

{"votes": {"funny": 2, "useful": 5, "cool": 1}, "user_id": "harveydennis", "name": "Jasmine Graham", "url": "http://example.org/user_details?userid=harveydennis", "average_stars": 3.5, "review_count": 12, "type": "user"}
{"votes": {"funny": 1, "useful": 2, "cool": 4}, "user_id": "njohnson", "name": "Zachary Ballard", "url": "https://www.example.com/user_details?userid=njohnson", "average_stars": 3.5, "review_count": 12, "type": "user"}
{"votes": {"funny": 1, "useful": 0, "cool": 4}, "user_id": "david06", "name": "Jonathan George", "url": "https://example.com/user_details?userid=david06", "average_stars": 3.5, "review_count": 12, "type": "user"}
{"votes": {"funny": 6, "useful": 5, "cool": 0}, "user_id": "santiagoerika", "name": "Amanda Taylor", "url": "https://www.example.com/user_details?userid=santiagoerika", "average_stars": 3.5, "review_count": 12, "type": "user"}
{"votes": {"funny": 1, "useful": 8, "cool": 2}, "user_id": "rodriguezdennis", "name": "Jennifer Roach", "url": "http://www.example.com/user_details?userid=rodriguezdennis", "average_stars": 3.5, "review_count": 12, "type": "user"}
Liczba Pi_
źródło

Odpowiedzi:

223

Masz plik tekstowy w formacie JSON Lines . Musisz przeanalizować plik wiersz po wierszu:

import json

data = []
with open('file') as f:
    for line in f:
        data.append(json.loads(line))

Każda linia zawiera prawidłowy kod JSON, ale jako całość nie jest prawidłową wartością JSON, ponieważ nie ma listy najwyższego poziomu ani definicji obiektu.

Zauważ, że ponieważ plik zawiera JSON w każdym wierszu, oszczędzasz sobie bólu głowy związanego z próbą przeanalizowania tego wszystkiego za jednym razem lub znalezienia strumieniowego parsera JSON. Możesz teraz zdecydować się na przetwarzanie każdego wiersza osobno przed przejściem do następnego, oszczędzając przy tym pamięć. Prawdopodobnie nie chcesz dołączać każdego wyniku do jednej listy, a następnie przetwarzać wszystkiego, jeśli plik jest naprawdę duży.

Jeśli masz plik zawierający pojedyncze obiekty JSON z separatorami między nimi, użyj Jak używać modułu „json” do odczytu jednego obiektu JSON naraz? aby przeanalizować poszczególne obiekty przy użyciu metody buforowanej.

Martijn Pieters
źródło
2
+1 Może warto zauważyć, że jeśli nie potrzebujesz wszystkich obiektów naraz, bardziej wydajnym podejściem może być przetwarzanie ich pojedynczo. W ten sposób nie będziesz musiał przechowywać w pamięci całych danych, ale pojedynczy fragment.
Tadeck
1
@Pi_: będziesz mieć słownik, więc po prostu wejdź na pola jako klucze:data = json.loads(line); print data[u'votes']
Martijn Pieters
1
@Pi_: wydrukuj wynik json.loads () lub użyj debugera do sprawdzenia.
Martijn Pieters
1
@Pi_: nie; nie myl formatu JSON z reprezentacją dyktowania w Pythonie. Widzisz teraz słowniki Pythona ze stringami.
Martijn Pieters
1
@ user2441441: zobacz link do odpowiedzi z posta tutaj.
Martijn Pieters
11

dla tych, którzy natkną się na to pytanie: jsonlinesbiblioteka Pythona (znacznie młodsza niż to pytanie) elegancko obsługuje pliki z jednym dokumentem json w wierszu. zobacz https://jsonlines.readthedocs.io/

wouter bolsterlee
źródło
4

To jest źle sformatowane. Masz jeden obiekt JSON w każdym wierszu, ale nie są one zawarte w większej strukturze danych (tj. Tablicy). Będziesz musiał przeformatować go tak, aby zaczynał się [i kończył ]przecinkiem na końcu każdego wiersza, lub przeanalizuj go wiersz po wierszu jako oddzielne słowniki.

Daniel Roseman
źródło
20
Z plikiem 50 MB prawdopodobnie lepiej radzi sobie z przesyłaniem danych linia po linii. :-)
Martijn Pieters
11
To, czy plik jest źle sformatowany, zależy od punktu widzenia. Jeśli miał być w formacie „linii JSON”, jest prawidłowy. Zobacz: jsonlines.org
LS