Python json.loads muestra ValueError: datos adicionales

151

Estoy obteniendo algunos datos de un archivo JSON "new.json", y quiero filtrar algunos datos y almacenarlos en un nuevo archivo JSON. Aquí está mi código:

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

y recibo un error, el rastreo es:

  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)

¿Alguien me puede ayudar?

Aquí hay una muestra de los datos en new.json, hay alrededor de 1500 diccionarios más en el archivo

{
    "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
fuente
Este es el error que obtiene cada vez que el JSON de entrada tiene más de un objeto por línea. Muchas de las respuestas aquí suponen que solo hay un objeto por línea, o construyen ejemplos obedeciendo eso, pero se romperían si ese no fuera el caso.
smci
@smci: ¿Puede explicar la líneamore than one object per line
Aspiring1

Respuestas:

150

Como puede ver en el siguiente ejemplo, json.loads(y json.load) no decodifica múltiples objetos 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 desea volcar varios diccionarios, envuélvalos en una lista, voltee la lista (en lugar de volcar los diccionarios varias veces)

>>> dict1 = {}
>>> dict2 = {}
>>> json.dumps([dict1, dict2])
'[{}, {}]'
>>> json.loads(json.dumps([dict1, dict2]))
[{}, {}]
falsetru
fuente
77
¿Puedes explicar de nuevo con referencia al código que di arriba? Soy un novato, y a veces me toma mucho tiempo comprender esas cosas.
Apoorv Ashutosh
1
@ApoorvAshutosh, parece que new.jsoncontiene un json y otros datos redundantes. json.load, json.loadssolo puede decodificar un json. Levanta un ValueErrorcuando encuentra datos adicionales como puede ver.
falsetru
He pegado una muestra de new.json, y estoy filtrando algunos datos de ella, por lo que no entiendo de dónde obtengo datos adicionales
Apoorv Ashutosh
1
@ApoorvAshutosh, Dijiste 1500 diccionarios más en la pregunta editada. Esa es la información adicional. Si usted fue quien hizo un new.json, simplemente coloque un solo json en un archivo.
falsetru
1
@ApoorvAshutosh, si necesita volcar varios diccionarios como json, envuélvalos en una lista y voltee la lista.
falsetru
100

Puede leer desde un archivo, jsonifyingcada línea a medida que avanza:

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

Esto evita almacenar objetos intermedios de python. Siempre que escriba un tweet completo por append()llamada, esto debería funcionar.

Adam Hughes
fuente
77
La respuesta aceptada aborda cómo solucionar el origen del problema si controla el proceso de exportación, pero si está utilizando los datos de otra persona y solo tiene que lidiar con ellos, este es un excelente método de bajo costo.
charlesreid1
3
Muchos conjuntos de datos (p. Ej., Conjuntos de datos de Yelp) hoy en día se proporcionan como "conjunto" de objetos Json y su enfoque es conveniente para cargarlos.
Gabrer el
36

Encontré esto porque estaba tratando de cargar un archivo JSON volcado de MongoDB. Me estaba dando un error

JSONDecodeError: Extra data: line 2 column 1

El volcado MongoDB JSON tiene un objeto por línea, así que lo que funcionó para mí es:

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

Esto también puede suceder si su archivo JSON no es solo 1 registro JSON. Un registro JSON se ve así:

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

Se abre y se cierra con un corchete [], dentro de los corchetes están los corchetes {}. Puede haber muchos pares de llaves, pero todo termina con una llave cerrada]. Si su archivo json contiene más de uno de esos:

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

entonces carga () fallará.

Verifiqué esto con mi propio archivo que estaba fallando.

import json

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

Esto funciona porque 1_guests.json tiene un registro []. El archivo original que estaba usando all_guests.json tenía 6 registros separados por nueva línea. Eliminé 5 registros (que ya verifiqué para que se corrigieran entre paréntesis) y guardé el archivo con un nuevo nombre. Entonces la declaración de cargas funcionó.

El error fue

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

PD. Uso la palabra registro, pero ese no es el nombre oficial. Además, si su archivo tiene caracteres de nueva línea como el mío, puede recorrerlo para cargar () un registro a la vez en una variable json.

VISQL
fuente
2
¿Hay alguna manera de json.loadsleer fragmentos json delimitados por nueva línea? Es decir, ¿actuar como [json.loads(x) for x in text.split('\n')]? Relacionado: ¿Existe una garantía que json.dumpsno incluirá nuevas líneas literales en su salida con sangría predeterminada?
Ben
1
@Ben, por defecto json.dumpscambiará las nuevas líneas en el contenido del texto a "\n", manteniendo su json en una sola línea.
jchook
7

Bueno, podría ayudar a alguien. acabo de recibir el mismo error mientras mi archivo json es así

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

y lo encontré malformado, así que lo cambié a una especie de

{
  "datas":[
    {"id":"1101010","city_id":"1101","name":"TEUPAH SELATAN"},
    {"id":"1101020","city_id":"1101","name":"SIMEULUE TIMUR"}
  ]
}
Akbar Noto
fuente
1
cargando igual que el tuyo, json.load (archivo)
Akbar Noto
6

Una línea para su problema:

data = [json.loads(line) for line in open('tweets.json', 'r')]
Nihal
fuente
1
Esta no es una solución general, supone que la entrada tiene un objeto JSON por línea, y lo rompe, no lo hace.
smci
3

Si quieres resolverlo en dos líneas puedes hacerlo así:

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

Creo que guardar los dictados en una lista no es una solución ideal aquí propuesta por @falsetru.

Mejor manera es, iterando a través de los dictados y guardándolos en .json agregando una nueva línea.

nuestros 2 diccionarios son

d1 = {'a':1}

d2 = {'b':2}

puedes escribirlos a .json

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

y puedes leer el archivo json sin ningún problema

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

simple y eficiente

murat yalçın
fuente
Esta no es una solución general, supone que la entrada tiene un objeto JSON por línea, y lo rompe, no lo hace.
smci