Dlaczego Python nie może przeanalizować tych danych JSON?


1438

Mam ten JSON w pliku:

{
    "maps": [
        {
            "id": "blabla",
            "iscategorical": "0"
        },
        {
            "id": "blabla",
            "iscategorical": "0"
        }
    ],
    "masks": [
        "id": "valore"
    ],
    "om_points": "value",
    "parameters": [
        "id": "valore"
    ]
}

Napisałem ten skrypt, aby wydrukować wszystkie dane JSON:

import json
from pprint import pprint

with open('data.json') as f:
    data = json.load(f)

pprint(data)

Ten program zgłasza wyjątek:

Traceback (most recent call last):
  File "<pyshell#1>", line 5, in <module>
    data = json.load(f)
  File "/usr/lib/python3.5/json/__init__.py", line 319, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python3.5/json/decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python3.5/json/decoder.py", line 355, in raw_decode
    obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Expecting ',' delimiter: line 13 column 13 (char 213)

Jak mogę przeanalizować JSON i wyodrębnić jego wartości?


@kederrac Z podanego powodu: „To pytanie było spowodowane literówką lub problemem, którego nie można już odtworzyć”. Json jest nieprawidłowy.
Rob

@kederrac Problem jest spowodowany błędem w użyciu, nie dlatego, że można go odtworzyć.
Rob

Odpowiedzi:


2127

Twoje dane są nieprawidłowe w formacie JSON . Masz, []kiedy powinieneś {}:

  • []są dla tablic JSON, które są wywoływane listw Pythonie
  • {}dotyczą obiektów JSON, które są wywoływane dictw języku Python

Oto jak powinien wyglądać Twój plik JSON:

{
    "maps": [
        {
            "id": "blabla",
            "iscategorical": "0"
        },
        {
            "id": "blabla",
            "iscategorical": "0"
        }
    ],
    "masks": {
        "id": "valore"
    },
    "om_points": "value",
    "parameters": {
        "id": "valore"
    }
}

Następnie możesz użyć swojego kodu:

import json
from pprint import pprint

with open('data.json') as f:
    data = json.load(f)

pprint(data)

Dzięki danym możesz teraz znaleźć takie wartości:

data["maps"][0]["id"]
data["masks"]["id"]
data["om_points"]

Wypróbuj je i sprawdź, czy to zaczyna mieć sens.


1
Ok, więc muszę kontrolować mój kod, ponieważ ten plik Json jest generowany z obiektu Java. Dzięki.
michele

5
Dzięki za rozwiązanie. Podczas drukowania otrzymuję symbol Unicode. (np. u'valore '). Jak temu zapobiec?
diaryfolio

6
Ładne, ale python dodaje u'przed każdym kluczem. Masz pomysł, dlaczego?
CodyBugstein,

7
Dlatego twój tekst to Unicode, a nie string. Większość czasu lepiej jest mieć tekst w Unicode dla niemieckich umlautów i do dzielenia się wynikami tekstowymi z innymi modułami / programami itp. Więc jesteś dobry!
Michael P.

2
Chciałbym dokonać obserwacji, która, mam nadzieję, jest pomocna i zdecydowanie ironiczna. Uważam, że moduł pprint jest gorszy od modułu json dla ładnego drukowania jsona. Jeśli spróbujesz obu, myślę, że się zgodzisz. Aby wyświetlić i debugować moje struktury danych json, robiłem: output = json.dumps (data_structure, indent = 2, sort_keys = True) print (output) Myślę, że znajdziesz kontrolę wcięcia, sortowanie i inteligentny zawijanie wierszy w metodzie dumps () tak, aby ci się podobało. Jeśli moje myślenie jest błędne, proszę dać mi znać.
Larold,

307

Twój data.jsonpowinien wyglądać tak:

{
 "maps":[
         {"id":"blabla","iscategorical":"0"},
         {"id":"blabla","iscategorical":"0"}
        ],
"masks":
         {"id":"valore"},
"om_points":"value",
"parameters":
         {"id":"valore"}
}

Twój kod powinien być:

import json
from pprint import pprint

with open('data.json') as data_file:    
    data = json.load(data_file)
pprint(data)

Zauważ, że działa to tylko w Pythonie 2.6 i withnowszych wersjach , ponieważ zależy to od -statement . W Pythonie 2.5 from __future__ import with_statement, w Pythonie <= 2.4, patrz odpowiedź Justina Peela , na której opiera się ta odpowiedź.

Możesz teraz uzyskać dostęp do pojedynczych wartości takich jak to:

data["maps"][0]["id"]  # will return 'blabla'
data["masks"]["id"]    # will return 'valore'
data["om_points"]      # will return 'value'

7
Mam opinię na ten temat. Może nie było jasne, dlaczego uważam, że potrzebna jest inna odpowiedź. Dodano uwagę na temat zgodności z instrukcją with.
Bengt

Przepraszamy za wycofanie, ale sugerowany kod będzie data_file openedytowany dłużej niż to konieczne.
Bengt,

Odwołując się do dokumentacji 2.6 ( docs.python.org/2.6/library/io.html ), otwarcie pliku w kontekście „z” spowoduje automatyczne zamknięcie pliku.
Steve S.

1
@SteveS. Tak, ale nie przed opuszczeniem kontekstu. pprinting w kontekście with-dotrzymuje data_fileotwarte dłużej.
Bengt,

1
@GayanPathirage go otworzyć jak data["om_points"], data["masks"]["id"]. Chodzi o to, że można osiągnąć dowolny poziom w słowniku, określając „ścieżki klucza”. Jeśli otrzymasz KeyErrorwyjątek, oznacza to, że klucz nie istnieje na ścieżce. Uważaj na literówki lub sprawdź strukturę swojego słownika.
Nuhman,

71

Odpowiedź Justina Peela jest naprawdę pomocna, ale jeśli używasz języka Python 3, czytanie JSON powinno wyglądać następująco:

with open('data.json', encoding='utf-8') as data_file:
    data = json.loads(data_file.read())

Uwaga: użyj json.loadszamiast json.load. W Pythonie 3 json.loadspobiera parametr ciągu. json.loadpobiera parametr obiektu podobny do pliku. data_file.read()zwraca obiekt ciągu.

Szczerze mówiąc, nie sądzę, aby w większości przypadków ładowanie wszystkich danych Json do pamięci stanowiło problem.


10
Dlaczego należy json.loadtego unikać .loadsw Pythonie 3?
Zearin,

10
Strona, do której prowadzi link, nie mówi nic o unikaniu load.
Dan Hulme

28
Ta odpowiedź czyta cały plik do pamięci, gdy nie jest to konieczne, i sugeruje, że w Pythonie 3 plików JSON nie można odczytać leniwie, co jest nieprawdą. Przepraszam, ale to oczywista opinia.
Łukasz Rogalski,

10
Ta odpowiedź nie jest dokładna. Nie ma powodu, aby nie używać pliku json.load z otwartą procedurą obsługi plików w python3. Przepraszamy za przegłosowanie, ale nie wydaje się, abyś uważnie przeczytał powyższe komentarze.
dusktreader 30.09.16

5
+1 Ta odpowiedź jest świetna! Dziękuję za to i odciągnąłem mnie od szukania funkcji, która może używać łańcuchów, ponieważ pracuję tylko z łańcuchami i żądaniami sieci, które nie są plikami!
newpeople

54
data = []
with codecs.open('d:\output.txt','rU','utf-8') as f:
    for line in f:
       data.append(json.loads(line))

8
jest to poprawne rozwiązanie, jeśli w pliku znajduje się wiele obiektów Json. json.loadsnie dekoduje wielu obiektów Json. W przeciwnym razie pojawi się błąd „Dodatkowe dane”.
yasin_alm

To najlepsza odpowiedź. W przeciwnym razie pojawia się błąd „Dodatkowe dane”.
Earthx9

39
Posiadanie wielu obiektów json w pliku oznacza, że ​​sam plik nie jest tak naprawdę prawidłowym plikiem json. Jeśli masz wiele obiektów do uwzględnienia w pliku json, powinny one być zawarte w tablicy na najwyższym poziomie pliku.
dusktreader 30.09.16

Posiadanie wielu obiektów Json w pliku oznacza, że ​​plik nie jest pojedynczym obiektem Json. To trochę oczywiste. Utworzenie jednej tablicy z obiektów jest oczywistym obejściem. Ale JSON jest zgodne z projektem jednoznacznie rozwiązana, na prawie każdym poziomie (przez }, ]lub "). W związku z tym można rzeczywiście łączyć wiele obiektów w jednym ciągu lub w jednym pliku, bez dwuznaczności. Problem polega na tym, że analizator składni oczekujący pojedynczego obiektu zawiedzie, gdy zostanie przekazany więcej niż jeden obiekt.
MSalters

Reklama przechowująca wiele obiektów JSON w jednym pliku: istnieje do tego „standard” - jsonlines.org/examples w .jsonl(linie json), obiekty są oddzielone znakiem nowej linii, co sprawia, że ​​wstępne przetwarzanie do parsowania jest banalne i pozwala do łatwego dzielenia / grupowania plików bez obawy o znaczniki początkowe / końcowe.
Sebi,

13

„Ultra JSON” lub po prostu „ujson” poradzi sobie z []wejściem do pliku JSON. Jeśli czytasz plik wejściowy JSON w swoim programie jako listę elementów JSON; takie jak [{[{}]}, {}, [], etc...]ujson może obsłużyć dowolną dowolną kolejność list słowników, słowników list.

Możesz znaleźć ujson w indeksie pakietu Python, a interfejs API jest prawie identyczny z biblioteką wbudowaną w Python json.

ujson jest również znacznie szybszy, jeśli ładujesz większe pliki JSON. Możesz zobaczyć szczegóły dotyczące wydajności w porównaniu z innymi bibliotekami JSON Pythona w tym samym podanym linku.


9

Jeśli używasz Python3, możesz spróbować zmienić swój ( connection.jsonplikowy) JSON na:

{
  "connection1": {
    "DSN": "con1",
    "UID": "abc",
    "PWD": "1234",
    "connection_string_python":"test1"
  }
  ,
  "connection2": {
    "DSN": "con2",
    "UID": "def",
    "PWD": "1234"
  }
}

Następnie za pomocą następującego kodu:

connection_file = open('connection.json', 'r')
conn_string = json.load(connection_file)
conn_string['connection1']['connection_string_python'])
connection_file.close()
>>> test1

1
działa to również w wersji 2.7.5
siddardha

17
pozostawia to otwarty uchwyt pliku. użycie withoświadczenia byłoby lepsze
Corey Goldberg,

6

Proszę przejść ze zmodyfikowanym data.jsonplikiem:

{
    "maps": [
        {
            "id": "blabla",
            "iscategorical": "0"
        },
        {
            "id": "blabla",
            "iscategorical": "0"
        }
    ],
    "masks": [{
        "id": "valore"
    }],
    "om_points": "value",
    "parameters": [{
        "id": "valore"
    }]
}

Możesz zadzwonić lub wydrukować dane na konsoli, używając poniższych wierszy:

import json
from pprint import pprint
with open('data.json') as data_file:
    data_item = json.load(data_file)
pprint(data_item)

Oczekiwany wynik dla print(data_item['parameters'][0]['id']):

{'maps': [{'id': 'blabla', 'iscategorical': '0'},
          {'id': 'blabla', 'iscategorical': '0'}],
 'masks': [{'id': 'valore'}],
 'om_points': 'value',
 'parameters': [{'id': 'valore'}]}

Oczekiwany wynik dla print(data_item['parameters'][0]['id']):

valore

Jeśli chcielibyśmy dodać kolumnę zliczającą liczbę obserwacji w „mapach”, jak moglibyśmy napisać tę funkcję?
Chenxi

5

Istnieją dwa typy tej analizy.

  1. Analizowanie danych z pliku ze ścieżki systemowej
  2. Analizowanie JSON ze zdalnego adresu URL.

Z pliku można użyć następujących opcji

import json
json = json.loads(open('/path/to/file.json').read())
value = json['key']
print json['value']

W tym artykule wyjaśniono pełne analizowanie i uzyskiwanie wartości przy użyciu dwóch scenariuszy. Analizowanie JSON przy użyciu Pythona


4

Jako użytkownik python3 ,

Różnica pomiędzy loadi loadsmetod jest szczególnie ważne podczas odczytu danych z pliku json.

Jak stwierdzono w dokumentach:

json.load:

Deserializuj fp (a .read () - obsługujący plik tekstowy lub plik binarny zawierający dokument JSON) do obiektu Python przy użyciu tej tabeli konwersji.

json.loads:

json.loads: Deserializuj s (instancję str, bytes lub bajtrayray zawierającą dokument JSON) do obiektu Python przy użyciu tej tabeli konwersji.

Metoda json.load może bezpośrednio odczytać otwarty dokument json, ponieważ jest w stanie odczytać plik binarny.

with open('./recipes.json') as data:
  all_recipes = json.load(data)

W rezultacie Twoje dane Json są dostępne w formacie określonym zgodnie z tą tabelą konwersji:

https://docs.python.org/3.7/library/json.html#json-to-py-table


Jak to jest odpowiedź na zadane pytanie? Użytkownik używał właściwej metody, aby załadować plik json.
Raj006,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.