Por que o Python não pode analisar esses dados JSON?

1439

Eu tenho esse JSON em um arquivo:

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

Eu escrevi este script para imprimir todos os dados JSON:

import json
from pprint import pprint

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

pprint(data)

Este programa gera uma exceção, no entanto:

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)

Como posso analisar o JSON e extrair seus valores?

michele
fonte
@kederrac Pelo motivo exposto: "Esta pergunta foi causada por um erro de digitação ou por um problema que não pode mais ser reproduzido". O json é inválido.
Rob
@kederrac O problema é causado por um erro no uso, não porque pode ser reproduzido.
Rob

Respostas:

2128

Seus dados não são no formato JSON válido . Você tem []quando deve ter {}:

  • []são para matrizes JSON, chamadas listem Python
  • {}são para objetos JSON, chamados dictem Python

Veja como seu arquivo JSON deve ficar:

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

Então você pode usar seu código:

import json
from pprint import pprint

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

pprint(data)

Com os dados, agora você também pode encontrar valores da seguinte forma:

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

Experimente e veja se isso faz sentido.

Justin Peel
fonte
1
Ok, então eu tenho que controlar meu código, porque este arquivo json é gerado a partir de um objeto java. Obrigado.
Michele 14/05
5
Obrigado pela solução. estou recebendo um símbolo unicode durante a impressão. (por exemplo, u'valore '). Como evitá-lo?
Diaryfolio
6
Bom, mas o python adiciona um u'antes de cada chave. Alguma idéia do porquê?
CodyBugstein
7
É por isso que seu texto é do tipo unicode e não string. Na maioria das vezes, é melhor ter texto em unicode para tremas alemães e compartilhar resultados de texto com outros módulos / programas etc. Então você é bom!
Michael P
2
Eu gostaria de fazer uma observação que, espero, seja útil e definitivamente irônica. Acho que o módulo pprint é inferior ao módulo json para o json de impressão bonita. Se você tentar os dois, acho que concorda. Para exibir e depurar minhas estruturas de dados json, venho fazendo: output = json.dumps (estrutura de dados, indent = 2, sort_keys = True) print (output) Acho que você encontrará o controle de indentação, classificação e inteligência quebra de linha no método dumps () para ser do seu agrado. Se meu pensamento estiver errado, alguém por favor me avise.
Larold 12/10
307

Você data.jsondeve ficar assim:

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

Seu código deve ser:

import json
from pprint import pprint

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

Observe que isso funciona apenas no Python 2.6 e withversões posteriores , pois depende da declaração- . No uso do Python 2.5 from __future__ import with_statement, no Python <= 2.4, consulte a resposta de Justin Peel , na qual essa resposta se baseia.

Agora você também pode acessar valores únicos como este:

data["maps"][0]["id"]  # will return 'blabla'
data["masks"]["id"]    # will return 'valore'
data["om_points"]      # will return 'value'
Bengt
fonte
7
Eu tenho um voto negativo sobre isso. Talvez não estivesse claro por que pensei que outra resposta era necessária. Nota adicionada sobre a compatibilidade da declaração with.
Bengt
Desculpe pela reversão, mas o código sugerido continuaria sendo data_file opened mais do que o necessário.
Bengt 25/05
Referindo-se à documentação 2.6 ( docs.python.org/2.6/library/io.html ), abrir um arquivo no contexto "com" fechará automaticamente o arquivo.
Steve S.
1
@SteveS. Sim, mas não antes do contexto ser deixado. pprintA withinserção no contexto-mantém a data_fileabertura por mais tempo.
Bengt
1
@GayanPathirage você acessá-lo, como data["om_points"], data["masks"]["id"]. A idéia é que você pode alcançar qualquer nível em um dicionário especificando os 'caminhos principais'. Se você receber uma KeyErrorexceção, significa que a chave não existe no caminho. Procure erros de digitação ou verifique a estrutura do seu dicionário.
Nuhman 25/05
71

A resposta de Justin Peel é realmente útil, mas se você estiver usando Python 3, a leitura JSON deve ser feita assim:

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

Nota: use em json.loadsvez de json.load. No Python 3, json.loadsusa um parâmetro de string. json.loadusa um parâmetro de objeto semelhante a arquivo. data_file.read()retorna um objeto string.

Para ser sincero, não acho que seja um problema carregar todos os dados json na memória na maioria dos casos.

Geng Jiawen
fonte
10
Por que deve json.loadser evitado em favor .loadsno Python 3?
Zearin 16/07/2015
10
A página que você vinculou não diz nada sobre como evitar load.
Dan Hulme
28
Esta resposta lê o arquivo inteiro na memória quando não é necessário e sugere que, no Python 3, os arquivos JSON não podem ser lidos preguiçosamente, o que é falso. Sinto muito, mas é claramente voto negativo.
Rogukasz Rogalski
10
Esta resposta não é precisa. Não há razão para não usar o json.load com um manipulador de arquivos aberto no python3. Desculpe pelo voto negativo, mas não parece que você leu os comentários acima com muito cuidado.
dusktreader
5
+1 Esta resposta é ótima! Obrigado por isso e me levou a ir longe por procurar uma função que possa usar strings, porque eu só trabalho com strings e solicitações de rede que não são arquivos!
New282
54
data = []
with codecs.open('d:\output.txt','rU','utf-8') as f:
    for line in f:
       data.append(json.loads(line))
user1743724
fonte
8
esta é a solução correta se você tiver vários objetos json em um arquivo. json.loadsnão decodifica vários objetos json. Caso contrário, você receberá o erro 'Dados extras'.
precisa saber é o seguinte
Esta é a melhor resposta. Caso contrário, ocorrerá o erro 'Dados extras'.
Earthx9
39
Ter vários objetos json em um arquivo significa que o arquivo em si não é realmente válido. Se você tiver vários objetos para incluir em um arquivo json, eles deverão estar contidos em uma matriz no nível superior do arquivo.
dusktreader
Ter vários objetos json em um arquivo significa que o arquivo não é um único objeto json. Isso é óbvio. Criar uma única matriz dos objetos é uma solução óbvia. Mas JSON é por design explicitamente revogadas, em quase todos os níveis (por }, ]ou "). Portanto, você pode concatenar vários objetos em uma única sequência ou arquivo único, sem ambiguidade. O problema aqui é que um analisador que espera um único objeto falha quando é passado mais de um objeto.
MSalters
Anúncio armazenando vários objetos JSON em um único arquivo: existe um "padrão" para isso - jsonlines.org/examples em .jsonl(linhas json), os objetos são separados por um caractere de nova linha que torna o pré-processamento para análise trivial e permite facilmente dividir / lote arquivos sem se preocupar com marcadores de início / fim.
Sebi
13

"Ultra JSON" ou simplesmente "ujson" podem lidar com []a entrada de arquivo JSON. Se você estiver lendo um arquivo de entrada JSON em seu programa como uma lista de elementos JSON; tais como, [{[{}]}, {}, [], etc...]ujson pode lidar com qualquer ordem arbitrária de listas de dicionários, dicionários de listas.

Você pode encontrar ujson no índice do pacote Python e a API é quase idêntica à jsonbiblioteca interna do Python .

O ujson também é muito mais rápido se você estiver carregando arquivos JSON maiores. Você pode ver os detalhes de desempenho em comparação com outras bibliotecas Python JSON no mesmo link fornecido.

moeabdol
fonte
9

Se você estiver usando o Python3, tente alterar seu connection.jsonJSON ( arquivo) para:

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

Em seguida, usando o seguinte 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
fonte
1
isso também funciona no 2.7.5
siddardha
17
isso deixa o identificador de arquivo aberto. usando uma withdeclaração seria melhor
Corey Goldberg
6

Aqui você vai com o data.jsonarquivo modificado :

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

Você pode ligar ou imprimir dados no console usando as linhas abaixo:

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

Saída prevista 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'}]}

Saída prevista para print(data_item['parameters'][0]['id']):

valore
JoboFive
fonte
Se quisermos adicionar uma coluna para contar quantas observações "mapas" têm, como poderíamos escrever essa função?
Chenxi
5

Existem dois tipos nessa análise.

  1. Analisando dados de um arquivo a partir de um caminho do sistema
  2. Analisando JSON a partir de URL remota.

Em um arquivo, você pode usar o seguinte

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

Este artigo explica a análise completa e a obtenção de valores usando dois cenários. Analisando JSON usando Python

Bibin Wilson
fonte
4

Como usuário python3 ,

A diferença entre loade loadsmétodos é importante, especialmente quando você lê dados json do arquivo.

Conforme declarado nos documentos:

json.load:

Desserialize fp (um arquivo .read () - suportando arquivo de texto ou arquivo binário que contém um documento JSON) para um objeto Python usando esta tabela de conversão.

json.loads:

json.loads: desserializa s (uma instância de str, bytes ou bytearray que contém um documento JSON) para um objeto Python usando esta tabela de conversão.

O método json.load pode ler diretamente o documento json aberto, pois é capaz de ler o arquivo binário.

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

Como resultado, seus dados json estão disponíveis como em um formato especificado de acordo com esta tabela de conversão:

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

muratgozel
fonte
Como isso é uma resposta para a pergunta? O usuário estava usando o método certo para carregar o arquivo json.
Raj006