¿Por qué Python no puede analizar estos datos JSON?

1439

Tengo este JSON en un archivo:

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

Escribí este script para imprimir todos los datos JSON:

import json
from pprint import pprint

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

pprint(data)

Sin embargo, este programa plantea una excepción:

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)

¿Cómo puedo analizar el JSON y extraer sus valores?

michele
fuente
@kederrac Por la razón dada: "Esta pregunta fue causada por un error tipográfico o un problema que ya no se puede reproducir". El json no es válido.
Rob
@kederrac El problema se debe a un error en el uso, no porque se pueda reproducir.
Rob

Respuestas:

2128

Sus datos no son válidos en formato JSON . Tienes []cuando deberías tener {}:

  • []son para matrices JSON, que se llaman listen Python
  • {}son para objetos JSON, que se llaman dicten Python

Así es como debería verse su archivo JSON:

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

Entonces puedes usar tu código:

import json
from pprint import pprint

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

pprint(data)

Con los datos, ahora también puede encontrar valores así:

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

Pruébelos y vea si comienza a tener sentido.

Justin Peel
fuente
1
Ok, tengo que controlar mi código porque este archivo json se genera a partir de un objeto java. Gracias.
michele
55
Gracias por la solucion. Recibo un símbolo Unicode al imprimirlo. (por ejemplo, u'valore '). ¿Cómo prevenirlo?
diaryfolio
66
Agradable pero Python agrega un u'antes de cada clave. ¿Alguna idea de por qué?
CodyBugstein
77
Es por eso que su texto es de tipo unicode, no de cadena. La mayoría de las veces es mejor tener texto en unicode para diéresis alemanas y compartir resultados de texto con otros módulos / programas, etc. ¡Entonces estás bien!
Michael P
2
Me gustaría hacer una observación que espero sea útil y definitivamente irónica. Me parece que el módulo pprint es inferior al módulo json para json de impresión bonita. Si los prueba a ambos, creo que estará de acuerdo. Para mostrar y depurar mis estructuras de datos json, he estado haciendo: output = json.dumps (data_structure, indent = 2, sort_keys = True) print (output) Creo que encontrarás el control de sangría, la clasificación y la inteligencia ajuste de línea en el método dumps () para que sea de su agrado. Si mi pensamiento es incorrecto, alguien por favor hágamelo saber.
Larold
307

Su data.jsondebe tener este aspecto:

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

Tu código debe ser:

import json
from pprint import pprint

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

Tenga en cuenta que esto solo funciona en Python 2.6 y withversiones posteriores, ya que depende de la declaración . En Python 2.5 from __future__ import with_statement, en Python <= 2.4, vea la respuesta de Justin Peel , en la que se basa esta respuesta.

Ahora también puede acceder a valores individuales como este:

data["maps"][0]["id"]  # will return 'blabla'
data["masks"]["id"]    # will return 'valore'
data["om_points"]      # will return 'value'
Bengt
fuente
77
Tengo un voto negativo sobre esto. Tal vez no estaba claro, por qué pensé que era necesaria otra respuesta. Se agregó una nota sobre la compatibilidad de la declaración con.
Bengt
Perdón por la reversión, pero el código sugerido se mantendría data_file openeditado más tiempo del necesario.
Bengt
En referencia a la documentación 2.6 ( docs.python.org/2.6/library/io.html ), abrir un archivo en el contexto "con" cerrará automáticamente el archivo.
Steve S.
1
@SteveS. Sí, pero no antes de dejar el contexto. pprinting en with-context mantiene la data_fileapertura por más tiempo.
Bengt
1
@GayanPathirage se accede a él como data["om_points"], data["masks"]["id"]. La idea es que puede alcanzar cualquier nivel en un diccionario especificando las 'rutas clave'. Si obtiene una KeyErrorexcepción, significa que la clave no existe en la ruta. Busque errores tipográficos o revise la estructura de su diccionario.
Nuhman
71

La respuesta de Justin Peel es realmente útil, pero si está utilizando Python 3, la lectura de JSON debe hacerse así:

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

Nota: use en json.loadslugar de json.load. En Python 3, json.loadstoma un parámetro de cadena. json.loadtoma un parámetro de objeto similar a un archivo. data_file.read()devuelve un objeto de cadena.

Para ser honesto, no creo que sea un problema cargar todos los datos json en la memoria la mayoría de los casos.

Geng Jiawen
fuente
10
¿Por qué debería json.loadevitarse .loadsen Python 3?
Zearin
10
La página que ha vinculado no dice nada sobre evitar load.
Dan Hulme
28
Esta respuesta lee todo el archivo en la memoria cuando no es necesario y sugiere que en Python 3 los archivos JSON no se pueden leer perezosamente, lo que no es cierto. Lo siento, pero es claro voto negativo.
Łukasz Rogalski
10
Esta respuesta no es precisa. No hay razón para no usar json.load con un controlador de archivo abierto en python3. Perdón por el voto negativo, pero no parece que hayas leído los comentarios anteriores con mucho cuidado.
dusktreader
55
+1 ¡Esta respuesta es genial! ¡Gracias por eso y me alejó de buscar una función que pueda usar cadenas porque solo trabajo con cadenas y solicitudes de red que no son archivos!
newpeople
54
data = []
with codecs.open('d:\output.txt','rU','utf-8') as f:
    for line in f:
       data.append(json.loads(line))
usuario1743724
fuente
8
Esta es la solución correcta si tiene múltiples objetos json en un archivo. json.loadsno decodifica múltiples objetos json. De lo contrario, obtendrá el error 'Datos adicionales'.
yasin_alm
Esta es la mejor respuesta. De lo contrario, da el error 'Datos adicionales'.
Earthx9
39
Tener varios objetos json en un archivo significa que el archivo en sí no es realmente json válido. Si tiene varios objetos para incluir en un archivo json, deben estar contenidos en una matriz en el nivel superior del archivo.
dusktreader
Tener múltiples objetos json en un archivo significa que el archivo no es un solo objeto json. Eso es algo obvio. Hacer una sola matriz de los objetos es una solución obvia. Pero JSON es por diseño explícitamente terminado, en casi todos los niveles (por }, ]o "). Por lo tanto, puede concatenar múltiples objetos en una sola cadena o un solo archivo, sin ambigüedad. El problema aquí es que un analizador que espera un solo objeto falla cuando se pasa más de un objeto.
MSalters
Anuncio que almacena múltiples objetos JSON en un solo archivo: hay un "estándar" para eso: jsonlines.org/examples en .jsonl(líneas json), los objetos están separados por un carácter de nueva línea que hace que el procesamiento previo para el análisis sea trivial y permite para dividir / procesar fácilmente archivos por lotes sin preocuparse por los marcadores de inicio / fin.
Sebi
13

"Ultra JSON" o simplemente "ujson" puede manejar tener []en su entrada de archivo JSON. Si está leyendo un archivo de entrada JSON en su programa como una lista de elementos JSON; tales como, [{[{}]}, {}, [], etc...]ujson puede manejar cualquier orden arbitrario de listas de diccionarios, diccionarios de listas.

Puede encontrar ujson en el índice del paquete Python y la API es casi idéntica a la jsonbiblioteca incorporada de Python .

ujson también es mucho más rápido si está cargando archivos JSON más grandes. Puede ver los detalles de rendimiento en comparación con otras bibliotecas JSON de Python en el mismo enlace proporcionado.

moeabdol
fuente
9

Si está utilizando Python3, puede intentar cambiar su connection.jsonJSON ( archivo) a:

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

Luego usando el siguiente código:

connection_file = open('connection.json', 'r')
conn_string = json.load(connection_file)
conn_string['connection1']['connection_string_python'])
connection_file.close()
>>> test1
sushmit
fuente
1
esto también funciona en
2.7.5
17
Esto deja abierto el identificador de archivo. usar una withdeclaración sería mejor
Corey Goldberg
6

Aquí tienes el data.jsonarchivo modificado :

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

Puede llamar o imprimir datos en la consola utilizando las siguientes líneas:

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

Salida esperada para print(data_item['parameters'][0]['id']):

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

Salida esperada para print(data_item['parameters'][0]['id']):

valore
JoboFive
fuente
Si quisiéramos agregar una columna para contar cuántas observaciones tienen los "mapas", ¿cómo podríamos escribir esta función?
Chenxi
5

Hay dos tipos en este análisis.

  1. Análisis de datos de un archivo desde una ruta del sistema
  2. Analizando JSON desde URL remota.

Desde un archivo, puede usar lo siguiente

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

Este artículo explica el análisis completo y la obtención de valores utilizando dos escenarios. Analizando JSON usando Python

Bibin Wilson
fuente
4

Como usuario de python3 ,

La diferencia entre loady los loadsmétodos es importante, especialmente cuando lee datos json del archivo.

Como se indica en los documentos:

json.load:

Deserialice fp (un .read (): archivo de texto compatible o archivo binario que contiene un documento JSON) a un objeto Python usando esta tabla de conversión.

json.loads:

json.loads: Deserialice s (una instancia de str, bytes o bytearray que contiene un documento JSON) a un objeto Python usando esta tabla de conversión.

El método json.load puede leer directamente el documento json abierto, ya que puede leer archivos binarios.

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

Como resultado, sus datos json están disponibles en un formato especificado de acuerdo con esta tabla de conversión:

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

muratgozel
fuente
¿Cómo es esta una respuesta a la pregunta que se hace? El usuario estaba usando el método correcto para cargar el archivo json.
Raj006