Perché Python non può analizzare questi dati JSON?


1439

Ho questo JSON in un file:

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

Ho scritto questo script per stampare tutti i dati JSON:

import json
from pprint import pprint

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

pprint(data)

Questo programma solleva un'eccezione, tuttavia:

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)

Come posso analizzare JSON ed estrarne i valori?


@kederrac Per il motivo indicato: "Questa domanda è stata causata da un errore di battitura o da un problema che non può più essere riprodotto". Il json non è valido.
Rob

@kederrac Il problema è causato da un errore nell'utilizzo non perché può essere riprodotto.
Rob

Risposte:


2128

I tuoi dati non sono in formato JSON valido . Hai []quando dovresti avere {}:

  • []sono per array JSON, che sono chiamati listin Python
  • {}sono per oggetti JSON, che sono chiamati dictin Python

Ecco come dovrebbe apparire il tuo file JSON:

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

Quindi puoi usare il tuo codice:

import json
from pprint import pprint

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

pprint(data)

Con i dati ora puoi trovare anche valori come questi:

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

Prova quelli e vedi se inizia a dare un senso.


1
Ok, quindi devo controllare il mio codice perché questo file json è generato da un oggetto Java. Grazie.
michele

5
Grazie per la soluzione Ricevo un simbolo Unicode durante la stampa. (es. u'valore '). Come prevenirlo?
diario del

6
Bello ma Python aggiunge un u'prima di ogni tasto. Qualche idea sul perché?
CodyBugstein il

7
Ecco perché il tuo testo è di tipo unicode e non stringa. La maggior parte delle volte è meglio avere un testo in unicode per le umlaut tedesche e per condividere i risultati del testo con altri moduli / programmi ecc. Quindi sei bravo!
Michael P,

2
Vorrei fare un'osservazione che si spera sia utile e decisamente ironica. Trovo che il modulo pprint sia inferiore al modulo json per la bella stampa json. Se li provi entrambi, penso che sarai d'accordo. Per visualizzare ed eseguire il debug delle mie strutture di dati json, ho fatto: output = json.dumps (data_structure, indent = 2, sort_keys = True) print (output) Penso che troverai il controllo del rientro, l'ordinamento e intelligente line-wrapping nel metodo dumps () per essere di tuo gradimento. Se il mio pensiero è sbagliato, qualcuno per favore fammi sapere.
Larold,

307

Il tuo data.jsondovrebbe assomigliare a questo:

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

Il tuo codice dovrebbe essere:

import json
from pprint import pprint

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

Nota che questo funziona solo in Python 2.6 e withversioni successive, in quanto dipende dallo stato . In Python 2.5 from __future__ import with_statement, in Python <= 2.4, vedi la risposta di Justin Peel , su cui si basa questa risposta.

Ora puoi anche accedere a singoli valori come questo:

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

7
Ho un voto negativo su questo. Forse non era chiaro, perché pensavo fosse necessaria un'altra risposta. Aggiunta nota sulla compatibilità dell'istruzione with.
Bengt,

Ci scusiamo per il rollback, ma il codice suggerito rimarrebbe data_file openpiù lungo del necessario.
Bengt,

Facendo riferimento alla documentazione 2.6 ( docs.python.org/2.6/library/io.html ), l'apertura di un file nel contesto "con" chiuderà automaticamente il file.
Steve S.

1
@SteveS. Sì, ma non prima di lasciare il contesto. pprinting nel with-contesto mantiene l' data_fileapertura più a lungo.
Bengt,

1
@GayanPathirage si accede come data["om_points"], data["masks"]["id"]. L'idea è che puoi raggiungere qualsiasi livello in un dizionario specificando i "percorsi chiave". Se ricevi KeyErrorun'eccezione significa che la chiave non esiste nel percorso. Cerca errori di battitura o controlla la struttura del dizionario.
Nuhman,

71

La risposta di Justin Peel è davvero utile, ma se stai usando Python 3 la lettura di JSON dovrebbe essere fatta così:

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

Nota: utilizzare json.loadsinvece di json.load. In Python 3, json.loadsaccetta un parametro stringa. json.loadaccetta un parametro oggetto simile a un file. data_file.read()restituisce un oggetto stringa.

Ad essere sincero, non penso che sia un problema caricare tutti i dati json in memoria nella maggior parte dei casi.


10
Perché dovrebbe json.loadessere evitato a favore di .loadsin Python 3?
Zearin,

10
La pagina che hai collegato non dice nulla sull'evitamento load.
Dan Hulme,

28
Questa risposta legge l'intero file in memoria quando non è necessario e suggerisce che in Python 3 i file JSON non possono essere letti pigramente, il che non è vero. Mi dispiace, ma è chiaro il voto negativo.
Łukasz Rogalski il

10
Questa risposta non è precisa. Non c'è motivo di non usare json.load con un gestore file aperto in python3. Ci scusiamo per il downvote, ma non sembra che tu abbia letto i commenti sopra con molta attenzione.
dusktreader,

5
+1 Questa risposta è fantastica! Grazie per questo e mi ha spinto ad andare lontano per cercare una funzione che può usare le stringhe perché lavoro solo con stringhe e richieste di rete che non sono file!
Newpeople,

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

8
questa è la soluzione corretta se si hanno più oggetti json in un file. json.loadsnon decodifica più oggetti json. In caso contrario, viene visualizzato l'errore "Dati aggiuntivi".
yasin_alm,

Questa è la risposta migliore In caso contrario, viene visualizzato l'errore "Dati aggiuntivi".
Earthx9,

39
Avere oggetti json multipli in un file significa che il file stesso non è effettivamente json valido. Se hai più oggetti da includere in un file json, dovrebbero essere contenuti in un array al livello superiore del file.
dusktreader,

Avere più oggetti JSON in un file significa che il file non è un singolo oggetto JSON. È abbastanza ovvio. Realizzare un singolo array dagli oggetti è una soluzione ovvia. Ma JSON è progettato in modo esplicito terminato, a quasi tutti i livelli (da }, ]o "). Quindi puoi concatenare più oggetti in una singola stringa o in un singolo file, senza ambiguità. Il problema qui è che un parser che si aspetta un singolo oggetto fallisce quando viene passato più di un oggetto.
MSalters

Annuncio che memorizza più oggetti JSON in un singolo file: esiste uno "standard" per questo - jsonlines.org/examples in .jsonl(linee json), gli oggetti sono separati da un carattere di nuova riga che rende la pre-elaborazione per l'analisi banale e consente per dividere facilmente / batch file senza preoccuparsi dei marcatori di inizio / fine.
Sebi,

13

"Ultra JSON" o semplicemente "ujson" sono in grado di gestire []l'input del file JSON. Se stai leggendo un file di input JSON nel tuo programma come un elenco di elementi JSON; come [{[{}]}, {}, [], etc...]ujson può gestire qualsiasi ordine arbitrario di elenchi di dizionari, dizionari di elenchi.

Puoi trovare ujson nell'indice del pacchetto Python e l'API è quasi identica alla jsonlibreria integrata di Python .

ujson è anche molto più veloce se stai caricando file JSON più grandi. Puoi vedere i dettagli delle prestazioni rispetto ad altre librerie Python JSON nello stesso link fornito.


9

Se stai usando Python3, puoi provare a cambiare il tuo ( connection.jsonfile) JSON in:

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

Quindi utilizzando il seguente codice:

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

1
questo funziona anche in 2.7.5
siddardha,

17
questo lascia aperto l'handle del file. usare una withdichiarazione sarebbe meglio
Corey Goldberg,

6

Qui vai con il data.jsonfile modificato :

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

È possibile chiamare o stampare i dati sulla console utilizzando le seguenti linee:

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

Uscita prevista per print(data_item['parameters'][0]['id']):

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

Uscita prevista per print(data_item['parameters'][0]['id']):

valore

Se desideriamo aggiungere una colonna per contare quante osservazioni ha "mappe", come potremmo scrivere questa funzione?
Chenxi

5

Esistono due tipi in questa analisi.

  1. Analisi dei dati da un file da un percorso di sistema
  2. Analisi di JSON dall'URL remoto.

Da un file, è possibile utilizzare quanto segue

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

Questo articolo illustra l'analisi completa e l'acquisizione di valori utilizzando due scenari. Analisi di JSON utilizzando Python


4

Come utente python3 ,

La differenza tra loade loadsmetodi è importante soprattutto quando leggi i dati json dal file.

Come indicato nei documenti:

json.load:

Deserializza fp (un file .read () - che supporta file di testo o file binario contenente un documento JSON) su un oggetto Python usando questa tabella di conversione.

json.loads:

json.loads: Deserializza s (un'istanza str, byte o bytearray contenente un documento JSON) su un oggetto Python usando questa tabella di conversione.

Il metodo json.load può leggere direttamente il documento json aperto poiché è in grado di leggere il file binario.

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

Di conseguenza, i tuoi dati json sono disponibili come in un formato specificato in base a questa tabella di conversione:

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


In che modo questa è una risposta alla domanda? L'utente stava usando il metodo giusto per caricare il file JSON.
Raj006,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.