Чому Python не може проаналізувати ці дані JSON?


1438

У мене цей JSON у файлі:

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

Я написав цей сценарій, щоб надрукувати всі дані JSON:

import json
from pprint import pprint

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

pprint(data)

Ця програма створює виняток, хоча:

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)

Як я можу розібрати JSON і витягти його значення?


@kederrac З наведеної причини: "Це питання було викликано помилковою помилкою або проблемою, яку неможливо більше відтворити". Json недійсний.
Роб

@kederrac Проблема викликана помилкою у використанні не тому, що вона може бути відтворена.
Роб

Відповіді:


2127

Ваші дані недійсні у форматі JSON . У вас є, []коли ви повинні мати {}:

  • []призначені для масивів JSON, які викликаються listв Python
  • {}призначені для об'єктів JSON, які називаються dictв Python

Ось як повинен виглядати ваш файл JSON:

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

Тоді ви можете використовувати свій код:

import json
from pprint import pprint

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

pprint(data)

За допомогою даних тепер можна також знайти такі значення:

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

Спробуйте їх і подивіться, чи це не має сенсу.


1
Гаразд, я повинен контролювати свій код, оскільки цей файл json генерується з об’єкта java. Дякую.
michele

5
Дякую за рішення. Я отримую символ unicode під час друку. (наприклад, u'valore '). Як запобігти?
щоденниковий портфоліо

6
Хороший, але пітон додає u'перед кожною клавішею. Будь-яка ідея чому?
CodyBugstein

7
Ось чому ваш текст вводить unicode не рядок. У більшості випадків краще мати текст в унікоді для німецьких умлаут та для обміну текстовими результатами з іншими модулями / програмами тощо. Значить, ти добрий!
Майкл П

2
Я хотів би зробити спостереження, яке, сподіваємось, корисне і, безумовно, іронічне. Я вважаю, що модуль pprint поступається модулю json для гарненького друку json. Якщо ви спробуєте їх обоє, я думаю, ви погодиться. Для відображення та відлагодження моїх структур даних json я робив: output = json.dumps (data_structure, indent = 2, sort_keys = True) print (output) загортання рядків методом dumps (), що вам подобається. Якщо моє мислення неправильне, хтось, будь ласка, повідомте мене.
Ларольд

307

Ви data.jsonповинні виглядати так:

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

Ваш код повинен бути:

import json
from pprint import pprint

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

Зауважте, що це працює лише в Python 2.6 і вище, оскільки це залежить від withзаяви . У застосуванні Python 2.5 from __future__ import with_statementу Python <= 2.4 див. Відповідь Джастіна Піла , на якій ґрунтується ця відповідь.

Тепер ви також можете отримати доступ до таких значень:

data["maps"][0]["id"]  # will return 'blabla'
data["masks"]["id"]    # will return 'valore'
data["om_points"]      # will return 'value'

7
Я отримав протиріччя з цього приводу. Можливо, було не ясно, чому я вважав, що потрібна ще одна відповідь. Додано примітку про сумісність з-заявою.
Бенгт

Вибачте за відкат, але запропонований код буде тримати data_file openредакцію довше, ніж потрібно.
Бенгт

Посилаючись на документацію 2.6 ( docs.python.org/2.6/library/io.html ), відкриття файлу в контексті "з" автоматично закриє файл.
Стів С.

1
@SteveS. Так, але не раніше, ніж залишається контекст. pprinting у with-контексті тримає data_fileвідкритим довше.
Бенгт

1
@GayanPathirage ви отримаєте доступ до нього , як data["om_points"], data["masks"]["id"]. Ідея полягає в тому, що ви можете досягти будь-якого рівня в словнику, вказавши "ключові шляхи". Якщо ви отримаєте KeyErrorвиняток, це означає, що ключ не існує в шляху. Слідкуйте за помилками друку або перевірте структуру свого словника.
Нюман

71

Відповідь Джастіна Піла дуже корисна, але якщо ви використовуєте Python 3, читання JSON слід зробити так:

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

Примітка: використовувати json.loadsзамість json.load. У Python 3 json.loadsприймає параметр рядка. json.loadприймає файловий параметр об'єкта. data_file.read()повертає об'єкт рядка.

Якщо чесно, я не думаю, що це проблема завантаження всіх даних json у пам'ять у більшості випадків.


10
Чому слід json.loadуникати на користь .loadsPython 3?
Зерін

10
Сторінка, на яку ви пов’язали, нічого не говорить про те, щоб уникнути load.
Dan Hulme

28
Ця відповідь читає весь файл в пам’яті, коли цього не потрібно, і говорить про те, що в Python 3 файли JSON не можна читати ліниво, що не відповідає дійсності. Вибачте, але це зрозуміло.
Łukasz Rogalski

10
Ця відповідь не є точною. Немає причин не використовувати json.load з відкритим обробником файлів у python3. Вибачте за заяву, але, схоже, ви дуже уважно читали вищезазначені коментарі.
dusktreader

5
+1 Ця відповідь чудова! Дякую за це і відтягнув мене далеко від пошуку функції, яка може використовувати рядки, тому що я працюю лише з рядками та мережевим запитом, які не є файлами!
люди

54
data = []
with codecs.open('d:\output.txt','rU','utf-8') as f:
    for line in f:
       data.append(json.loads(line))

8
це правильне рішення, якщо у вас є кілька об’єктів json у файлі. json.loadsне декодує кілька об'єктів json. В іншому випадку ви отримуєте помилку "Додаткові дані".
yasin_alm

Це найкраща відповідь. В іншому випадку це дає помилку "Додаткові дані".
Earthx9

39
Наявність у файлі mutliple json об'єктів означає, що сам файл насправді не є дійсним json. Якщо у файл json є кілька об'єктів, вони повинні міститись у масиві на верхньому рівні файлу.
dusktreader

Наявність у файлі декількох об'єктів json означає, що файл не є єдиним об'єктом json. Це щось очевидно. Створення одного масиву з об'єктів очевидне вирішення. Але JSON є дизайн явно припинено, майже на кожному рівні (по }, ]або "). Отже, ви дійсно можете об'єднати кілька об’єктів в один рядок або один файл, без двозначності. Проблема тут полягає в тому, що аналізатор, який очікує на один об'єкт, не вдається, коли йому передано більше одного об'єкта.
MSalters

Оголошення зберігання декількох об'єктів JSON в одному файлі: є «стандарт» для цього - jsonlines.org/examples в .jsonl(JSON лінія), об'єкти розділені символом нового рядка , що робить попередню обробку для розбору тривіальними, і дозволяє легко розділяти / пакетні файли, не переживаючи маркери початку та кінця.
Sebi

13

"Ultra JSON" або просто "ujson" може працювати з наявністю []у вашому введенні файлу JSON. Якщо ви читаєте вхідний файл JSON у програму у вигляді списку елементів JSON; наприклад, [{[{}]}, {}, [], etc...]ujson може обробляти будь-який довільний порядок списків словників, словників списків.

Ви можете знайти ujson в індексі пакету Python, і API майже ідентичний вбудованій jsonбібліотеці Python .

ujson також набагато швидше, якщо ви завантажуєте більші файли JSON. Ви можете побачити деталі продуктивності порівняно з іншими бібліотеками Python JSON за тим самим наданим посиланням.


9

Якщо ви використовуєте Python3, ви можете спробувати змінити ( connection.jsonфайл) JSON на:

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

Потім використовуйте наступний код:

connection_file = open('connection.json', 'r')
conn_string = json.load(connection_file)
conn_string['connection1']['connection_string_python'])
connection_file.close()
>>> test1

1
це також працює в 2.7.5
siddardha

17
це залишає ручку файлу відкритою. використовувати withзаяву було б краще
Corey Goldberg

6

Тут ви перейдете з модифікованим data.jsonфайлом:

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

Ви можете дзвонити або друкувати дані на консолі, використовуючи рядки нижче:

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

Очікуваний вихід для print(data_item['parameters'][0]['id']):

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

Очікуваний вихід для print(data_item['parameters'][0]['id']):

valore

Якщо ми хотіли б додати стовпчик для підрахунку, скільки спостережень має "карти", як ми могли написати цю функцію?
Ченьсі,

5

У цьому розборі є два типи.

  1. Розбір даних із файлу із системного шляху
  2. Розбір JSON з віддаленої URL-адреси.

З файлу ви можете використовувати наступне

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

Ця стаття пояснює повний аналіз та отримання значень за допомогою двох сценаріїв. Розбір JSON за допомогою Python


4

Як користувач python3 ,

Різниця між loadі loadsметодами має важливе значення , особливо , коли ви читаєте JSon дані з файлу.

Як зазначено в документах:

json.load:

Десеріалізувати fp (a .read () - текстовий файл, що підтримує або двійковий файл, що містить документ JSON), до об’єкта Python, використовуючи цю таблицю перетворення.

json.loads:

json.loads: Десеріалізуйте s (str, байти або екземпляр байта, що містить документ JSON) до об'єкта Python, використовуючи цю таблицю перетворення.

Метод json.load може безпосередньо читати відкритий документ json, оскільки він може читати бінарний файл.

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

Як результат, ваші дані json доступні у форматі, визначеному відповідно до цієї таблиці переходів:

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


Як це відповідь на поставлене запитання? Користувач використовував правильний метод для завантаження файлу json.
Raj006
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.