Python Json加载()返回字符串而不是字典?

Posted

技术标签:

【中文标题】Python Json加载()返回字符串而不是字典?【英文标题】:Python Json loads() returning string instead of dictionary? 【发布时间】:2014-10-26 03:19:49 【问题描述】:

我正在尝试使用 Python 3 的内置 JSON 模块进行一些简单的 JSON 解析,并且通过阅读有关 SO 和谷歌搜索的一堆其他问题,这似乎应该非常简单。但是,我认为我得到的是返回的字符串而不是预期的字典。

首先,这是我试图从中获取值的 JSON。这只是 Twitter API 的一些输出

['in_reply_to_status_id_str': None, 'in_reply_to_screen_name': None, 'retweeted':     False, 'in_reply_to_status_id': None, 'contributors': None, 'favorite_count': 0, 'in_reply_to_user_id': None, 'coordinates': None, 'source': '<a href="http://twitter.com" rel="nofollow">Twitter Web Client</a>', 'geo': None, 'retweet_count': 0, 'text': 'Tweeting a url \nhttp://t.co/QDVYv6bV90', 'created_at': 'Mon Sep 01 19:36:25 +0000 2014', 'entities': 'symbols': [], 'user_mentions': [], 'urls': ['expanded_url': 'http://www.isthereanappthat.com', 'display_url': 'isthereanappthat.com', 'url': 'http://t.co/QDVYv6bV90', 'indices': [16, 38]], 'hashtags': [], 'id_str': '506526005943865344', 'in_reply_to_user_id_str': None, 'truncated': False, 'favorited': False, 'lang': 'en', 'possibly_sensitive': False, 'id': 506526005943865344, 'user': 'profile_text_color': '333333', 'time_zone': None, 'entities': 'description': 'urls': [], 'url': None, 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'protected': False, 'default_profile_image': True, 'utc_offset': None, 'default_profile': True, 'screen_name': 'KickzWatch', 'follow_request_sent': False, 'following': False, 'profile_background_color': 'C0DEED', 'notifications': False, 'description': '', 'profile_sidebar_border_color': 'C0DEED', 'geo_enabled': False, 'verified': False, 'friends_count': 40, 'created_at': 'Mon Sep 01 16:29:18 +0000 2014', 'is_translator': False, 'profile_sidebar_fill_color': 'DDEEF6', 'statuses_count': 4, 'location': '', 'id_str': '2784389341', 'followers_count': 4, 'favourites_count': 0, 'contributors_enabled': False, 'is_translation_enabled': False, 'lang': 'en', 'profile_image_url': 'http://abs.twimg.com/sticky/default_profile_images/default_profile_6_normal.png', 'profile_image_url_https': 'https://abs.twimg.com/sticky/default_profile_images/default_profile_6_normal.png', 'id': 2784389341, 'profile_use_background_image': True, 'listed_count': 0, 'profile_background_tile': False, 'name': 'Maktub Destiny', 'profile_link_color': '0084B4', 'place': None]

我将此字符串分配给一个名为 json_string 的变量,如下所示:

json_string = json.dumps(output)
jason = json.loads(json_string)

然后,当我尝试从“jason”字典中获取特定键时:

print(jason['hashtags'])

我收到一个错误:

TypeError: string indices must be integers

我希望能够将 json 输出转换为字典,然后使用 jason[key_name] 调用使用指定键获取值。我在这里有什么明显的遗漏吗?

这是我从 Java 毕业后第一次使用 Python。我非常喜欢这种语言,并认为它非常强大。因此,我们将不胜感激任何帮助!

【问题讨论】:

1) 您粘贴的数据是 Python 数据结构,而不是 JSON。 2) 外部数据结构是list,而不是字典。 @LukasGraf 嗯,很有趣。所以它是一个包含字典的列表?我只是注释掉了 json 逻辑,只是尝试了 output[0]['hashtags'] 没有运气。在这种情况下,“输出”是调用返回的 Python 数据结构。关于如何解决这个问题的任何想法? 正如其他人指出的那样,您的 JSON 输入将在 Python 中变为 list ,而不是 dict 。此外,由于缺少右括号,您提供的代码 sn-p print(jason['hashtags'] 甚至不是有效的 Python。请发布一个语法正确的示例及其输出,以便我们确定是什么代码产生了什么错误。 我得到一个不同的错误:TypeError: list indices must be integers, not str。这就是我所期望的:结果对象是一个列表,而不是一个字符串。 &gt;&gt;&gt; import json &gt;&gt;&gt; json_string = json.dumps(output) &gt;&gt;&gt; jason = json.loads(json_string) &gt;&gt;&gt; print(jason['hashtags']) Traceback (most recent call last): File "&lt;stdin&gt;", line 1, in &lt;module&gt; TypeError: list indices must be integers, not str 甚至不是有效的 JSON,它只允许双引号字符串,不允许单引号字符串。 【参考方案1】:

我做了 json.loads(json.loads(string)) 并且能够得到字典。你可以检查一下。第一次它不仅返回相同的字符串,而且处理它(例如删除 \ 字符。

【讨论】:

【参考方案2】:

好的,首先你应该打印你的对象以便你可以阅读它:

>>> from pprint import pprint
>>> output = ['in_reply_to_status_id_str': None, 'in_reply_to_screen_name': None, 'retweeted':     False, 'in_reply_to_status_id': None, 'contributors': None, 'favorite_count': 0, 'in_reply_to_user_id': None, 'coordinates': None, 'source': '<a href="http://twitter.com" rel="nofollow">Twitter Web Client</a>', 'geo': None, 'retweet_count': 0, 'text': 'Tweeting a url \nhttp://t.co/QDVYv6bV90', 'created_at': 'Mon Sep 01 19:36:25 +0000 2014', 'entities': 'symbols': [], 'user_mentions': [], 'urls': ['expanded_url': 'http://www.isthereanappthat.com', 'display_url': 'isthereanappthat.com', 'url': 'http://t.co/QDVYv6bV90', 'indices': [16, 38]], 'hashtags': [], 'id_str': '506526005943865344', 'in_reply_to_user_id_str': None, 'truncated': False, 'favorited': False, 'lang': 'en', 'possibly_sensitive': False, 'id': 506526005943865344, 'user': 'profile_text_color': '333333', 'time_zone': None, 'entities': 'description': 'urls': [], 'url': None, 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png', 'protected': False, 'default_profile_image': True, 'utc_offset': None, 'default_profile': True, 'screen_name': 'KickzWatch', 'follow_request_sent': False, 'following': False, 'profile_background_color': 'C0DEED', 'notifications': False, 'description': '', 'profile_sidebar_border_color': 'C0DEED', 'geo_enabled': False, 'verified': False, 'friends_count': 40, 'created_at': 'Mon Sep 01 16:29:18 +0000 2014', 'is_translator': False, 'profile_sidebar_fill_color': 'DDEEF6', 'statuses_count': 4, 'location': '', 'id_str': '2784389341', 'followers_count': 4, 'favourites_count': 0, 'contributors_enabled': False, 'is_translation_enabled': False, 'lang': 'en', 'profile_image_url': 'http://abs.twimg.com/sticky/default_profile_images/default_profile_6_normal.png', 'profile_image_url_https': 'https://abs.twimg.com/sticky/default_profile_images/default_profile_6_normal.png', 'id': 2784389341, 'profile_use_background_image': True, 'listed_count': 0, 'profile_background_tile': False, 'name': 'Maktub Destiny', 'profile_link_color': '0084B4', 'place': None]
>>> pprint(output)
['contributors': None,
  'coordinates': None,
  'created_at': 'Mon Sep 01 19:36:25 +0000 2014',
  'entities': 'hashtags': [],
               'symbols': [],
               'urls': ['display_url': 'isthereanappthat.com',
                         'expanded_url': 'http://www.isthereanappthat.com',
                         'indices': [16, 38],
                         'url': 'http://t.co/QDVYv6bV90'],
               'user_mentions': [],
  'favorite_count': 0,
  'favorited': False,
  'geo': None,
  'id': 506526005943865344,
  'id_str': '506526005943865344',
  'in_reply_to_screen_name': None,
  'in_reply_to_status_id': None,
  'in_reply_to_status_id_str': None,
  'in_reply_to_user_id': None,
  'in_reply_to_user_id_str': None,
  'lang': 'en',
  'place': None,
  'possibly_sensitive': False,
  'retweet_count': 0,
  'retweeted': False,
  'source': '<a href="http://twitter.com" rel="nofollow">Twitter Web Client</a>',
  'text': 'Tweeting a url \nhttp://t.co/QDVYv6bV90',
  'truncated': False,
  'user': 'contributors_enabled': False,
           'created_at': 'Mon Sep 01 16:29:18 +0000 2014',
           'default_profile': True,
           'default_profile_image': True,
           'description': '',
           'entities': 'description': 'urls': [],
           'favourites_count': 0,
           'follow_request_sent': False,
           'followers_count': 4,
           'following': False,
           'friends_count': 40,
           'geo_enabled': False,
           'id': 2784389341,
           'id_str': '2784389341',
           'is_translation_enabled': False,
           'is_translator': False,
           'lang': 'en',
           'listed_count': 0,
           'location': '',
           'name': 'Maktub Destiny',
           'notifications': False,
           'profile_background_color': 'C0DEED',
           'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme1/bg.png',
           'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme1/bg.png',
           'profile_background_tile': False,
           'profile_image_url': 'http://abs.twimg.com/sticky/default_profile_images/default_profile_6_normal.png',
           'profile_image_url_https': 'https://abs.twimg.com/sticky/default_profile_images/default_profile_6_normal.png',
           'profile_link_color': '0084B4',
           'profile_sidebar_border_color': 'C0DEED',
           'profile_sidebar_fill_color': 'DDEEF6',
           'profile_text_color': '333333',
           'profile_use_background_image': True,
           'protected': False,
           'screen_name': 'KickzWatch',
           'statuses_count': 4,
           'time_zone': None,
           'url': None,
           'utc_offset': None,
           'verified': False]

从这里你可以看到输出是一个list,其中包含一个dict。要访问它,您需要:

>>> first_elem = output[0]

您还将看到first_elem 中的hashtags 键包含在entities 键下的第二级dict 中:

>>> entities = first_elem['entities']
>>> pprint(entities)
'hashtags': [],
 'symbols': [],
 'urls': ['display_url': 'isthereanappthat.com',
           'expanded_url': 'http://www.isthereanappthat.com',
           'indices': [16, 38],
           'url': 'http://t.co/QDVYv6bV90'],
 'user_mentions': []

现在您可以访问hashtags

>>> entities['hashtags']
[]

这恰好是一个空列表。

要转换为 JSON,请注意注释:

>>> import json
>>> # Make sure output is the list object not a string representing the object
>>> json_string = json.dumps(output)
>>> jason = json.loads(output)
>>> jason[0]['entities']['hashtags']
[]

我认为您的问题是您在 json.dumps 之前输出了一个字符串,这意味着 json.loads 将返回一个字符串,而不是一个 json 对象。

@Dan 的回答是正确的,这不是有效的 JSON。然而,它是一个有效的 python 字典,我假设你使用 python 从 Twitter 获取它然后打印它。

【讨论】:

他的问题在于他将已经是 Python 的结果编码回 JSON,然后再次返回 Python,然后遇到另一个不相关的问题 ;-) 我将恢复对问题的编辑 - 如果问题保持其原始形式,您的回答会更有意义。 @Lukas ...好吧,如果您想获得技术...:P 简而言之,dict --> json_dumps() --> json_loads() 将返回您 dictstring--> json_dumps() --> json_loads() 会返回字符串。你所给予的就是你所得到的。这是业力【参考方案3】:

首先,您的 JSON 示例不是有效的 JSON; Twitter API 不会输出这个,因为它会破坏所有符合标准的 JSON 消费者。

jsonlint 显示了第一个明显的语法错误:单引号而不是双引号字符串。 其次,您有 None,其中 JSON 需要 nullFalse 而不是 falseTrue,而不是 true

您所谓的“JSON”示例似乎已被预解码为 Python :)。当我使用真实 JSON 的 sn-p 时,它的工作原理完全符合预期:

import json

json_string = r"""
["actual_json_key":"actual_json_value"]
"""

jason = json.loads(json_string)

print(jason[0]["actual_json_key"])

【讨论】:

以上是关于Python Json加载()返回字符串而不是字典?的主要内容,如果未能解决你的问题,请参考以下文章

追加到 json 中转储的字典列表,而不用 python 加载列表

.get() 返回字母而不是字符串

json.loads() 返回一个 unicode 对象而不是字典

对 Python 返回 JSON 作为字符串而不是文字感到困惑

如何在Python中将json.loads作为列表而不是字典[重复]

如何比较每个字典中 JSON Array 键值的字符串以查看它们是不是包含 NSUserDefault 字符串并返回 JSON 字典匹配项