Python:解析JSON时遇到KeyError问题

3

我刚刚编写了一个解析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"
  }
}

1
除非我漏掉了什么,否则看起来"plain""739c5b1cd5681e668f689aa66bcc254c"的子键。 - Morgan Thrapp
@MorganThrapp 我正在尝试获取 "test",而不是 plain 本身。 - Uber
@KevinGuan 真的是这样,user3554031的答案对我很有用,我只是不明白为什么我必须使用parsed_json['739c5b1cd5681e668f689aa66bcc254c']。 - Uber
@KevinGuan 哦,现在我有点明白了,会继续研究的,谢谢! - Uber
1
好的,不用谢 :) - Remi Guan
显示剩余2条评论
2个回答

3

当您可以看到您要定位数据的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.92.7.103.3.53.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"

我可以问一个问题吗?如果739c5b1cd5681e668f689aa66bcc254c不同怎么办?因为哈希值每次都会不同,如何使其动态地抓取呢? - Uber
@user3104326 参考示例#2,以更加优雅的方式处理动态键。 - jesterjunk
1
@user3104326 示例 #2 现在更加健壮,使用了 MD5 正则表达式匹配键,这样做更好,因为它不仅检查长度是否为32,还检查它是否只包含有效的MD5哈希中的字符。请注意,我只允许小写字母字符和数字。 - jesterjunk
哦,我明白了,那真的是一个很棒的程序啊,但是我找到了一种在明文之前做哈希的方法,因为我可以直接使用我放入的哈希值:)无论如何,你介意我把我的完成代码发给你看看吗?另外,我使用的api允许几乎任何未加盐的哈希值;) - Uber

1
在你的数据中,'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"
    }
}

谢谢,它起作用了,我现在可以测试了。为什么它是那个的成员,像一个标题之类的东西吗(对编程新手,从未使用过JSON)? - Uber

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接