Python json.loads affiche ValueError: données supplémentaires

151

J'obtiens des données à partir d'un fichier JSON "new.json" et je souhaite filtrer certaines données et les stocker dans un nouveau fichier JSON. Voici mon code:

import json
with open('new.json') as infile:
    data = json.load(infile)
for item in data:
    iden = item.get["id"]
    a = item.get["a"]
    b = item.get["b"]
    c = item.get["c"]
    if c == 'XYZ' or  "XYZ" in data["text"]:
        filename = 'abc.json'
    try:
        outfile = open(filename,'ab')
    except:
        outfile = open(filename,'wb')
    obj_json={}
    obj_json["ID"] = iden
    obj_json["VAL_A"] = a
    obj_json["VAL_B"] = b

et j'obtiens une erreur, le traçage est:

  File "rtfav.py", line 3, in <module>
    data = json.load(infile)
  File "/usr/lib64/python2.7/json/__init__.py", line 278, in load
    **kw)
  File "/usr/lib64/python2.7/json/__init__.py", line 326, in loads
    return _default_decoder.decode(s)
  File "/usr/lib64/python2.7/json/decoder.py", line 369, in decode
    raise ValueError(errmsg("Extra data", s, end, len(s)))
ValueError: Extra data: line 88 column 2 - line 50607 column 2 (char 3077 - 1868399)

Est-ce que quelqu'un peut m'aider?

Voici un échantillon des données dans new.json, il y a environ 1500 autres dictionnaires de ce type dans le fichier

{
    "contributors": null, 
    "truncated": false, 
    "text": "@HomeShop18 #DreamJob to professional rafter", 
    "in_reply_to_status_id": null, 
    "id": 421584490452893696, 
    "favorite_count": 0, 
    "source": "<a href=\"https://mobile.twitter.com\" rel=\"nofollow\">Mobile Web (M2)</a>", 
    "retweeted": false, 
    "coordinates": null, 
    "entities": {
        "symbols": [], 
        "user_mentions": [
            {
                "id": 183093247, 
                "indices": [
                    0, 
                    11
                ], 
                "id_str": "183093247", 
                "screen_name": "HomeShop18", 
                "name": "HomeShop18"
            }
        ], 
        "hashtags": [
            {
                "indices": [
                    12, 
                    21
                ], 
                "text": "DreamJob"
            }
        ], 
        "urls": []
    }, 
    "in_reply_to_screen_name": "HomeShop18", 
    "id_str": "421584490452893696", 
    "retweet_count": 0, 
    "in_reply_to_user_id": 183093247, 
    "favorited": false, 
    "user": {
        "follow_request_sent": null, 
        "profile_use_background_image": true, 
        "default_profile_image": false, 
        "id": 2254546045, 
        "verified": false, 
        "profile_image_url_https": "https://pbs.twimg.com/profile_images/413952088880594944/rcdr59OY_normal.jpeg", 
        "profile_sidebar_fill_color": "171106", 
        "profile_text_color": "8A7302", 
        "followers_count": 87, 
        "profile_sidebar_border_color": "BCB302", 
        "id_str": "2254546045", 
        "profile_background_color": "0F0A02", 
        "listed_count": 1, 
        "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png", 
        "utc_offset": null, 
        "statuses_count": 9793, 
        "description": "Rafter. Rafting is what I do. Me aur mera Tablet.  Technocrat of Future", 
        "friends_count": 231, 
        "location": "", 
        "profile_link_color": "473623", 
        "profile_image_url": "http://pbs.twimg.com/profile_images/413952088880594944/rcdr59OY_normal.jpeg", 
        "following": null, 
        "geo_enabled": false, 
        "profile_banner_url": "https://pbs.twimg.com/profile_banners/2254546045/1388065343", 
        "profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png", 
        "name": "Jayy", 
        "lang": "en", 
        "profile_background_tile": false, 
        "favourites_count": 41, 
        "screen_name": "JzayyPsingh", 
        "notifications": null, 
        "url": null, 
        "created_at": "Fri Dec 20 05:46:00 +0000 2013", 
        "contributors_enabled": false, 
        "time_zone": null, 
        "protected": false, 
        "default_profile": false, 
        "is_translator": false
    }, 
    "geo": null, 
    "in_reply_to_user_id_str": "183093247", 
    "lang": "en", 
    "created_at": "Fri Jan 10 10:09:09 +0000 2014", 
    "filter_level": "medium", 
    "in_reply_to_status_id_str": null, 
    "place": null
} 
Apoorv Ashutosh
la source
Il s'agit de l'erreur que vous obtenez chaque fois que le JSON d'entrée a plus d'un objet par ligne. Beaucoup de réponses ici supposent qu'il n'y a qu'un seul objet par ligne, ou construisent des exemples obéissant à cela, mais se briseraient si ce n'était pas le cas.
smci le
@smci: Pouvez-vous expliquer la lignemore than one object per line
aspirant1

Réponses:

150

Comme vous pouvez le voir dans l'exemple suivant, json.loads(and json.load) ne décode pas plusieurs objets json.

>>> json.loads('{}')
{}
>>> json.loads('{}{}') # == json.loads(json.dumps({}) + json.dumps({}))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python27\lib\json\__init__.py", line 338, in loads
    return _default_decoder.decode(s)
  File "C:\Python27\lib\json\decoder.py", line 368, in decode
    raise ValueError(errmsg("Extra data", s, end, len(s)))
ValueError: Extra data: line 1 column 3 - line 1 column 5 (char 2 - 4)

Si vous souhaitez vider plusieurs dictionnaires, mettez-les dans une liste, vider la liste (au lieu de vider les dictionnaires plusieurs fois)

>>> dict1 = {}
>>> dict2 = {}
>>> json.dumps([dict1, dict2])
'[{}, {}]'
>>> json.loads(json.dumps([dict1, dict2]))
[{}, {}]
falsetru
la source
7
Pouvez-vous expliquer à nouveau en référence au code que j'ai donné ci-dessus? Je suis un débutant, et parfois je prends beaucoup de temps pour comprendre de telles choses.
Apoorv Ashutosh
1
@ApoorvAshutosh, il semble new.jsoncontenir un json et une autre donnée redondante. json.load, json.loadsne peut décoder qu'un json. Il soulève un ValueErrorquand il rencontre des données supplémentaires comme vous le voyez.
falsetru
J'ai collé un échantillon de new.json, et j'en filtre certaines données, donc je ne sais pas d'où je
tire
1
@ApoorvAshutosh, Vous avez dit 1500 autres dictionnaires de ce type dans la question éditée. Ce sont les données supplémentaires. Si vous êtes celui qui a créé un new.json, mettez simplement un seul json dans un fichier.
falsetru
1
@ApoorvAshutosh, Si vous devez vider plusieurs dictionnaires en json, mettez-les dans une liste et vider la liste.
falsetru
101

Vous pouvez simplement lire à partir d'un fichier, jsonifyingchaque ligne au fur et à mesure:

tweets = []
for line in open('tweets.json', 'r'):
    tweets.append(json.loads(line))

Cela évite de stocker des objets Python intermédiaires. Tant que vous écrivez un tweet complet par append()appel, cela devrait fonctionner.

Adam Hughes
la source
7
La réponse acceptée traite de la manière de résoudre la source du problème si vous contrôlez le processus d'exportation, mais si vous utilisez les données de quelqu'un d'autre et que vous n'avez qu'à y faire face, c'est une excellente méthode à faible coût.
charlesreid1
3
De nos jours, de nombreux ensembles de données (par exemple: l'ensemble de données Yelp) sont fournis sous la forme d'un «ensemble» d'objets Json et votre approche est pratique pour les charger.
Gabrer
36

Je suis tombé sur cela parce que j'essayais de charger un fichier JSON vidé de MongoDB. Ça me donnait une erreur

JSONDecodeError: Extra data: line 2 column 1

Le vidage JSON MongoDB a un objet par ligne, donc ce qui a fonctionné pour moi est:

import json
data = [json.loads(line) for line in open('data.json', 'r')]
Nic Scozzaro
la source
13

Cela peut également se produire si votre fichier JSON n'est pas qu'un seul enregistrement JSON. Un enregistrement JSON ressemble à ceci:

[{"some data": value, "next key": "another value"}]

Il s'ouvre et se ferme avec un crochet [], entre les crochets se trouvent les accolades {}. Il peut y avoir plusieurs paires d'accolades, mais tout se termine par une parenthèse étroite]. Si votre fichier json en contient plusieurs:

[{"some data": value, "next key": "another value"}]
[{"2nd record data": value, "2nd record key": "another value"}]

puis load () échouera.

J'ai vérifié cela avec mon propre fichier qui échouait.

import json

guestFile = open("1_guests.json",'r')
guestData = guestFile.read()
guestFile.close()
gdfJson = json.loads(guestData)

Cela fonctionne car 1_guests.json a un enregistrement []. Le fichier original que j'utilisais all_guests.json avait 6 enregistrements séparés par une nouvelle ligne. J'ai supprimé 5 enregistrements (dont j'ai déjà vérifié qu'ils étaient réservés par des crochets) et enregistré le fichier sous un nouveau nom. Ensuite, la déclaration de charges a fonctionné.

L'erreur était

   raise ValueError(errmsg("Extra data", s, end, len(s)))
ValueError: Extra data: line 2 column 1 - line 10 column 1 (char 261900 - 6964758)

PS. J'utilise le mot record, mais ce n'est pas le nom officiel. De plus, si votre fichier contient des caractères de nouvelle ligne comme le mien, vous pouvez le parcourir pour charger () un enregistrement à la fois dans une variable json.

VISQL
la source
2
Existe-t-il un moyen de json.loadslire les morceaux json délimités par une nouvelle ligne? Autrement dit, pour agir comme [json.loads(x) for x in text.split('\n')]? Lié: Y a-t-il une garantie qui json.dumpsn'inclura pas les sauts de ligne littéraux dans sa sortie avec l'indentation par défaut?
Ben
1
@Ben, par défaut json.dumps, changera les nouvelles lignes dans le contenu du texte en "\n", en gardant votre json sur une seule ligne.
jchook le
7

Eh bien, cela pourrait aider quelqu'un. je viens de recevoir la même erreur alors que mon fichier json est comme ça

{"id":"1101010","city_id":"1101","name":"TEUPAH SELATAN"}
{"id":"1101020","city_id":"1101","name":"SIMEULUE TIMUR"}

et je l'ai trouvé mal formé, alors je l'ai changé en une sorte de

{
  "datas":[
    {"id":"1101010","city_id":"1101","name":"TEUPAH SELATAN"},
    {"id":"1101020","city_id":"1101","name":"SIMEULUE TIMUR"}
  ]
}
Akbar Noto
la source
1
chargement comme le vôtre, json.load (infile)
Akbar Noto
6

One-liner pour votre problème:

data = [json.loads(line) for line in open('tweets.json', 'r')]
Nihal
la source
1
Ce n'est pas une solution générale, cela suppose que l'entrée a un objet JSON par ligne et la casse, ce n'est pas le cas.
smci le
3

Si vous voulez le résoudre en deux lignes, vous pouvez le faire comme ceci:

with open('data.json') as f:
    data = [json.loads(line) for line in f]
coreehi
la source
1

Je pense que sauvegarder des dictionnaires dans une liste n'est pas une solution idéale proposée ici par @falsetru.

Le meilleur moyen est de parcourir les dictionnaires et de les enregistrer dans .json en ajoutant une nouvelle ligne.

nos 2 dictionnaires sont

d1 = {'a':1}

d2 = {'b':2}

vous pouvez les écrire en .json

import json
with open('sample.json','a') as sample:
    for dict in [d1,d2]:
        sample.write('{}\n'.format(json.dumps(dict)))

et vous pouvez lire le fichier json sans aucun problème

with open('sample.json','r') as sample:
    for line in sample:
        line = json.loads(line.strip())

simple et efficace

murat yalçın
la source
Ce n'est pas une solution générale, cela suppose que l'entrée a un objet JSON par ligne et la casse, ce n'est pas le cas.
smci le