Pourquoi Python ne peut-il pas analyser ces données JSON?

1439

J'ai ce JSON dans un fichier:

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

J'ai écrit ce script pour imprimer toutes les données JSON:

import json
from pprint import pprint

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

pprint(data)

Ce programme soulève cependant une exception:

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)

Comment analyser le JSON et extraire ses valeurs?

michele
la source
@kederrac Pour la raison donnée: "Cette question a été causée par une faute de frappe ou un problème qui ne peut plus être reproduit." Le json n'est pas valide.
Rob
@kederrac Le problème est dû à une erreur d'utilisation non pas parce qu'il peut être reproduit.
Rob

Réponses:

2128

Vos données ne sont pas au format JSON valide . Vous avez []quand vous devriez avoir {}:

  • []sont pour les tableaux JSON, qui sont appelés listen Python
  • {}sont pour les objets JSON, qui sont appelés dicten Python

Voici à quoi devrait ressembler votre fichier JSON:

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

Ensuite, vous pouvez utiliser votre code:

import json
from pprint import pprint

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

pprint(data)

Avec les données, vous pouvez désormais également trouver des valeurs comme ceci:

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

Essayez-les et voyez si cela commence à avoir un sens.

Justin Peel
la source
1
Ok donc je dois contrôler mon code car ce fichier json est généré à partir d'un objet java. Merci.
michele
5
Merci pour la solution. je reçois un symbole unicode lors de l'impression. (par exemple u'valore '). Comment l'empêcher?
agenda
6
Sympa mais python ajoute un u'avant chaque touche. Une idée pourquoi?
CodyBugstein
7
C'est pourquoi votre texte est de type unicode et non chaîne. La plupart du temps, il est préférable d'avoir du texte en unicode pour les trémas allemands et de partager les résultats du texte avec d'autres modules / programmes, etc. Alors tu es bon!
Michael P
2
Je voudrais faire une observation qui, je l'espère, sera utile et certainement ironique. Je trouve que le module pprint est inférieur au module json pour json joliment imprimé. Si vous les essayez tous les deux, je pense que vous serez d'accord. Pour afficher et déboguer mes structures de données json, j'ai fait: output = json.dumps (data_structure, indent = 2, sort_keys = True) print (output) Je pense que vous trouverez le contrôle de retrait, le tri et l'intelligence l'habillage de ligne dans la méthode dumps () pour être tout à fait à votre goût. Si ma pensée est fausse, quelqu'un me le fait savoir.
Larold
307

Votre data.jsondevrait ressembler à ceci:

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

Votre code doit être:

import json
from pprint import pprint

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

Notez que cela ne fonctionne que dans Python 2.6 et withversions ultérieures, car cela dépend de la déclaration . En utilisation Python 2.5 from __future__ import with_statement, en Python <= 2.4, voir la réponse de Justin Peel , sur laquelle cette réponse est basée.

Vous pouvez désormais également accéder à des valeurs uniques comme celle-ci:

data["maps"][0]["id"]  # will return 'blabla'
data["masks"]["id"]    # will return 'valore'
data["om_points"]      # will return 'value'
Bengt
la source
7
J'ai eu un downvote à ce sujet. Peut-être que ce n'était pas clair, pourquoi je pensais qu'une autre réponse était nécessaire. Ajout d'une note sur la compatibilité de l'instruction with.
Bengt
Désolé pour la restauration, mais le code suggéré serait conservé data_file openplus longtemps que nécessaire.
Bengt
En se référant à la documentation 2.6 ( docs.python.org/2.6/library/io.html ), l'ouverture d'un fichier dans le contexte "avec" fermera automatiquement le fichier.
Steve S.16
1
@SteveS. Oui, mais pas avant que le contexte ne soit quitté. pprinting dans le with-contexte garde l' data_fileouvert plus longtemps.
Bengt
1
@GayanPathirage vous accédez comme data["om_points"], data["masks"]["id"]. L'idée est que vous pouvez atteindre n'importe quel niveau dans un dictionnaire en spécifiant les «chemins d'accès clés». Si vous obtenez une KeyErrorexception, cela signifie que la clé n'existe pas dans le chemin. Recherchez les fautes de frappe ou vérifiez la structure de votre dictionnaire.
Nuhman
71

La réponse de Justin Peel est vraiment utile, mais si vous utilisez Python 3, la lecture de JSON devrait se faire comme ceci:

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

Remarque: utilisez json.loadsau lieu de json.load. En Python 3, json.loadsprend un paramètre de chaîne. json.loadprend un paramètre d'objet de type fichier. data_file.read()renvoie un objet chaîne.

Pour être honnête, je ne pense pas que ce soit un problème de charger toutes les données json en mémoire dans la plupart des cas.

Geng Jiawen
la source
10
Pourquoi devrait- json.loadon éviter en faveur de .loadsPython 3?
Zearin
10
La page que vous avez liée ne dit rien sur l'évitement load.
Dan Hulme
28
Cette réponse lit le fichier entier en mémoire lorsqu'il n'est pas nécessaire et suggère qu'en Python 3, les fichiers JSON ne peuvent pas être lus paresseusement, ce qui est faux. Je suis désolé, mais c'est clairement un vote négatif.
Łukasz Rogalski
10
Cette réponse n'est pas exacte. Il n'y a aucune raison de ne pas utiliser json.load avec un gestionnaire de fichiers ouvert en python3. Désolé pour le downvote, mais il ne semble pas que vous ayez lu très attentivement les commentaires ci-dessus.
dusktreader
5
+1 Cette réponse est excellente! Merci pour cela et m'a poussé à aller loin pour chercher une fonction qui peut utiliser des chaînes car je ne travaille qu'avec des chaînes et des requêtes réseau qui ne sont pas des fichiers!
newpeople
54
data = []
with codecs.open('d:\output.txt','rU','utf-8') as f:
    for line in f:
       data.append(json.loads(line))
user1743724
la source
8
c'est la bonne solution si vous avez plusieurs objets json dans un fichier. json.loadsne décode pas plusieurs objets json. Sinon, vous obtenez l'erreur «Extra Data».
yasin_alm
C'est la meilleure réponse. Sinon, cela donne une erreur «Extra Data».
Earthx9
39
Le fait d'avoir plusieurs objets json dans un fichier signifie que le fichier lui-même n'est pas réellement un json valide. Si vous avez plusieurs objets à inclure dans un fichier json, ils doivent être contenus dans un tableau au niveau supérieur du fichier.
dusktreader
Le fait d'avoir plusieurs objets json dans un fichier signifie que le fichier n'est pas un seul objet json. C'est assez évident. La création d'un seul tableau à partir des objets est une solution de contournement évidente. Mais JSON est explicitement par la conception terminée, à presque tous les niveaux (par }, ]ou "). Ainsi, vous pouvez en effet concaténer plusieurs objets dans une seule chaîne ou un seul fichier, sans ambiguïté. Le problème ici est qu'un analyseur qui attend un seul objet échoue lorsqu'il passe plus d'un objet.
MSalters
Annonce stockant plusieurs objets JSON dans un seul fichier: il existe un "standard" pour cela - jsonlines.org/examples dans .jsonl(lignes json), les objets sont séparés par un caractère de nouvelle ligne qui rend le pré-traitement pour l'analyse syntaxique trivial, et permet pour diviser facilement / fichiers batch sans se soucier des marqueurs de début / fin.
Sebi
13

"Ultra JSON" ou simplement "ujson" peut gérer avoir []dans votre entrée de fichier JSON. Si vous lisez un fichier d'entrée JSON dans votre programme sous la forme d'une liste d'éléments JSON; tels que, [{[{}]}, {}, [], etc...]ujson peut gérer n'importe quel ordre arbitraire de listes de dictionnaires, de dictionnaires de listes.

Vous pouvez trouver ujson dans l' index du package Python et l'API est presque identique à la jsonbibliothèque intégrée de Python .

ujson est également beaucoup plus rapide si vous chargez des fichiers JSON plus volumineux. Vous pouvez voir les détails des performances par rapport aux autres bibliothèques Python JSON dans le même lien fourni.

moeabdol
la source
9

Si vous utilisez Python3, vous pouvez essayer de changer votre ( connection.jsonfichier) JSON en:

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

Puis en utilisant le code suivant:

connection_file = open('connection.json', 'r')
conn_string = json.load(connection_file)
conn_string['connection1']['connection_string_python'])
connection_file.close()
>>> test1
sushmit
la source
1
cela fonctionne également dans 2.7.5
siddardha
17
cela laisse la poignée de fichier ouverte. utiliser une withdéclaration serait mieux
Corey Goldberg
6

Ici vous allez avec un data.jsonfichier modifié :

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

Vous pouvez appeler ou imprimer des données sur la console en utilisant les lignes ci-dessous:

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

Sortie attendue pour print(data_item['parameters'][0]['id']):

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

Sortie attendue pour print(data_item['parameters'][0]['id']):

valore
JoboFive
la source
Si nous aimerions ajouter une colonne pour compter le nombre d'observations des "cartes", comment pourrions-nous écrire cette fonction?
Chenxi
5

Il existe deux types dans cette analyse.

  1. Analyser les données d'un fichier à partir d'un chemin système
  2. Analyser JSON à partir d'une URL distante.

À partir d'un fichier, vous pouvez utiliser les éléments suivants

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

Cet arcticle explique l'analyse complète et l'obtention de valeurs à l'aide de deux scénarios. Analyser JSON à l'aide de Python

Bibin Wilson
la source
4

En tant qu'utilisateur python3 ,

La différence entre les méthodes loadet loadsest importante, en particulier lorsque vous lisez des données json à partir d'un fichier.

Comme indiqué dans les documents:

json.load:

Désérialiser fp (un .read () - fichier texte ou fichier binaire contenant un document JSON) en un objet Python à l'aide de cette table de conversion.

json.loads:

json.loads: désérialiser s (une instance de str, bytes ou bytearray contenant un document JSON) vers un objet Python à l'aide de cette table de conversion.

La méthode json.load peut lire directement le document json ouvert car elle est capable de lire le fichier binaire.

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

En conséquence, vos données json sont disponibles dans un format spécifié selon cette table de conversion:

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

muratgozel
la source
Comment est-ce une réponse à la question posée? L'utilisateur utilisait la bonne méthode pour charger le fichier json.
Raj006