Chargement et analyse d'un fichier JSON avec plusieurs objets JSON

101

J'essaye de charger et d'analyser un fichier JSON en Python . Mais je suis bloqué en essayant de charger le fichier:

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

Rendements:

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

J'ai regardé 18,2. json- Encodeur et décodeur JSON dans la documentation Python, mais il est assez décourageant de lire cette documentation horrible.

Premières lignes (anonymisées avec des entrées aléatoires):

{"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"}
Pi_
la source

Réponses:

222

Vous disposez d'un fichier texte au format JSON Lines . Vous devez analyser votre fichier ligne par ligne:

import json

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

Chaque ligne contient du JSON valide, mais dans son ensemble, ce n'est pas une valeur JSON valide car il n'y a pas de liste de niveau supérieur ou de définition d'objet.

Notez que parce que le fichier contient du JSON par ligne, vous évitez les maux de tête d'essayer de tout analyser en une seule fois ou de trouver un analyseur JSON en streaming. Vous pouvez maintenant choisir de traiter chaque ligne séparément avant de passer à la suivante, en économisant de la mémoire dans le processus. Vous ne voulez probablement pas ajouter chaque résultat à une liste, puis tout traiter si votre fichier est vraiment volumineux.

Si vous avez un fichier contenant des objets JSON individuels avec des délimiteurs entre les deux, utilisez Comment utiliser le module 'json' pour lire un objet JSON à la fois? pour analyser des objets individuels à l'aide d'une méthode tamponnée.

Martijn Pieters
la source
2
+1 Peut-être qu'il vaut la peine de noter que si vous n'avez pas besoin de tous les objets à la fois, les traiter un par un peut être une approche plus efficace. De cette façon, vous n'aurez pas besoin de stocker des données entières dans la mémoire, mais une seule partie de celles-ci.
Tadeck
1
@Pi_: vous aurez un dictionnaire, alors accédez simplement aux champs sous forme de clés:data = json.loads(line); print data[u'votes']
Martijn Pieters
1
@Pi_: affichez ensuite le résultat de json.loads () ou utilisez le débogueur pour inspecter.
Martijn Pieters
1
@Pi_: non; ne confondez pas le format JSON avec la représentation python dict. Vous voyez maintenant des dictionnaires python avec des chaînes.
Martijn Pieters
1
@ user2441441: voir la réponse liée du message ici.
Martijn Pieters
11

pour ceux qui tombent sur cette question: la jsonlinesbibliothèque python (bien plus jeune que cette question) gère élégamment les fichiers avec un document json par ligne. voir https://jsonlines.readthedocs.io/

wouter bolsterlee
la source
4

C'est mal formaté. Vous avez un objet JSON par ligne, mais ils ne sont pas contenus dans une structure de données plus grande (c'est-à-dire un tableau). Vous devrez soit le reformater pour qu'il commence par [et se termine par ]une virgule à la fin de chaque ligne, soit l'analyser ligne par ligne comme des dictionnaires distincts.

Daniel Roseman
la source
20
Avec un fichier de 50 Mo, l'OP est probablement mieux de traiter les données ligne par ligne de toute façon. :-)
Martijn Pieters
11
Le fait que le fichier soit mal formaté dépend de son point de vue. S'il était destiné à être au format "lignes JSON", il est valide. Voir: jsonlines.org
LS