Python: получение Keyerror при разборе JSON

Я только что сделал программу для анализа некоторых данных из API. API возвращает данные в формате JSON. Когда я пытаюсь разобрать его, он выдает ключевую ошибку

Traceback (most recent call last):
  File "test.py", line 20, in <module>
    print(parsed_json['plain'])
KeyError: 'plain'

Это часть кода, которая имеет значение (остальное только для создания URL-адреса, работает отлично)

response = urllib.request.urlopen(url2).read()
strr = str(response)


if "plain" in strr:
    parsed_json = json.loads(response.decode("UTF-8"))
    print(parsed_json['plain'])
elif "INVALID HASH" in strr:
    print("You have entered an invalid hash.")
elif "NOT FOUND" in strr:
    print("The hash is not found")
elif "LIMIT REACHED" in strr:
    print("You have reached the max requests per minute, please try again in one minute.")

Я пытаюсь получить данные в обычном поле. Вот вывод из API:

{
  "REQUEST": "FOUND",
  "739c5b1cd5681e668f689aa66bcc254c": {
    "plain": "test",
    "hexplain": "74657374",
    "algorithm": "MD5X5PLAIN"
  }
}

person Uber    schedule 17.10.2015    source источник
comment
Если я что-то не упустил, похоже, что "plain" является подразделом "739c5b1cd5681e668f689aa66bcc254c".   -  person Morgan Thrapp    schedule 17.10.2015
comment
@MorganThrapp Я пытаюсь пройти тест после простого. Сам по себе не простой.   -  person Uber    schedule 17.10.2015
comment
"test" верно ли значение ключа "plain"?   -  person Casimir Crystal    schedule 17.10.2015
comment
@KevinGuan Это действительно так, ответ пользователя 3554031 сработал для меня, я просто не понимаю, почему мне пришлось использовать parsed_json['739c5b1cd5681e668f689aa66bcc254c']   -  person Uber    schedule 17.10.2015
comment
Поскольку "test" — это словарь внутри словаря '739c5b1cd5681e668f689aa66bcc254c'.   -  person Casimir Crystal    schedule 17.10.2015
comment
@KevinGuan Ага, теперь я вроде понял, буду продолжать разбираться, спасибо!   -  person Uber    schedule 17.10.2015
comment
Хорошо, пожалуйста :)   -  person Casimir Crystal    schedule 17.10.2015


Ответы (2)


Гораздо проще увидеть, что происходит, когда вы видите вложенную структуру объекта JSON, внутри которого вы пытаетесь получить данные:

Рабочий пример №1 — протестировано с Python 2.6.9 и 2.7.10 и 3.3.5 и >3.5.0

import json

json_string = '''
{
    "REQUEST": "FOUND",
    "739c5b1cd5681e668f689aa66bcc254c": {
        "plain": "test",
        "hexplain": "74657374",
        "algorithm": "MD5X5PLAIN"
    }
}
'''

if 'plain' in json_string:
    parsed_json = json.loads(json_string)
    print(parsed_json['739c5b1cd5681e668f689aa66bcc254c']['plain'])

'plain' является потомком '739c5b1cd5681e668f689aa66bcc254c'


Изменить

Следующий пример перебирает parsed_json и проверяет каждый ключ на длину 32 символа, а также проверяет, есть ли у ключа дочернее значение «plain» внутри него.

Рабочий пример №2 — протестировано с Python 2.6.9 и 2.7.10 и 3.3.5 и >3.5.0

import json
import re

def is_MD5(s):
    return True if re.match(r"([a-f\d]{32})", key) else False

strr = '''
{
    "REQUEST": "FOUND",
    "739c5b1cd5681e668f689aa66bcc254c": {
        "plain": "test",
        "hexplain": "74657374",
        "algorithm": "MD5X5PLAIN"
    }
}
'''

parsed_json = json.loads(strr)

for key, value in parsed_json.items():
    if is_MD5(key) and 'plain' in parsed_json[key]:
        xHash = key
        xPlain = parsed_json[key]['plain']

        print('value in key "plain" in key "{0}" is "{1}"'.format(*[xHash,
                                                                    xPlain]))

Вывод

the value of key "plain" in key "739c5b1cd5681e668f689aa66bcc254c" is "test"
person jesterjunk    schedule 17.10.2015
comment
Один вопрос, если можно спросить, а если 739c5b1cd5681e668f689aa66bcc254c другой? Поскольку хеш будет все время разным, как сделать его как бы динамическим, чтобы он тоже его захватывал? - person Uber; 18.10.2015
comment
@user3104326 user3104326 см. Пример № 2 для гораздо более элегантного решения для обработки динамического ключа. - person jesterjunk; 19.10.2015
comment
@ user3104326 Пример № 2 теперь более надежен с соответствием регулярному выражению MD5 для ключа, это лучше, потому что он не только проверяет, что длина равна 32, но также проверяет, содержит ли он только символы, которые находятся в допустимом хеше MD5. Обратите внимание, что я разрешил использовать только строчные буквы алфавита и цифры. - person jesterjunk; 19.10.2015
comment
Ааа, я вижу, ну, это действительно хорошая программа, чувак, но я нашел способ сделать эту хеш-вещь раньше, чем просто, потому что я могу просто использовать хэш, который я вставил :), в любом случае, не возражаете, если я пришлю вам свой готовый код, чтобы вы могли его посмотреть? Кроме того, API, который я использую, позволяет использовать практически любой хэш, который не содержит соли;) - person Uber; 19.10.2015

В ваших данных 'plain' не является членом parsed_json. Он является членом группы parsed_json['739c5b1cd5681e668f689aa66bcc254c']. Так что parsed_json['739c5b1cd5681e668f689aa66bcc254c']['plain'] должно работать.

JSON — это иерархическая структура данных. Скобки верхнего уровня указывают, что все это — один объект, который будет назначен parsed_json. Каждый член является парой имя-значение; значение 'REQUEST' равно 'FOUND'. Однако значение '739c5b1cd5681e668f689aa66bcc254c' является подобъектом, обозначенным открывающей скобкой. Его участниками являются 'plain', 'hexplain' и 'algorithm'. Это должно быть более ясно, если я напишу это так:

parsed_json: {
    "REQUEST":"FOUND",
    "739c5b1cd5681e668f689aa66bcc254c": {
        "plain":"test",
        "hexplain":"74657374",
        "algorithm":"MD5X5PLAIN"
    }
}
person user3553031    schedule 17.10.2015
comment
Спасибо, это сработало, и теперь я получаю тест. Почему это член этого, это как название или что-то в этом роде (новичок в программировании, никогда не использовал json) - person Uber; 17.10.2015