检查json输出中的键是否存在

时间:2018-08-29 13:29:26

标签: python

尝试解析某些json时,我始终收到以下错误:

Traceback (most recent call last):
  File "/Users/batch/projects/kl-api/api/helpers.py", line 37, in collect_youtube_data
    keywords = channel_info_response_data['items'][0]['brandingSettings']['channel']['keywords']
KeyError: 'brandingSettings'

在将其分配给变量之前,如何确保检查JSON输出的密钥?如果找不到密钥,那么我只想分配一个默认值。下面的代码:

try:
    channel_id = channel_id_response_data['items'][0]['id']
    channel_info_url = YOUTUBE_URL + '/channels/?key=' + YOUTUBE_API_KEY + '&id=' + channel_id + '&part=snippet,contentDetails,statistics,brandingSettings'
    print('Querying:', channel_info_url)
    channel_info_response = requests.get(channel_info_url)
    channel_info_response_data = json.loads(channel_info_response.content)
    no_of_videos = int(channel_info_response_data['items'][0]['statistics']['videoCount'])
    no_of_subscribers = int(channel_info_response_data['items'][0]['statistics']['subscriberCount'])
    no_of_views = int(channel_info_response_data['items'][0]['statistics']['viewCount'])
    avg_views = round(no_of_views / no_of_videos, 0)
    photo = channel_info_response_data['items'][0]['snippet']['thumbnails']['high']['url']
    description = channel_info_response_data['items'][0]['snippet']['description']
    start_date = channel_info_response_data['items'][0]['snippet']['publishedAt']
    title = channel_info_response_data['items'][0]['snippet']['title']
    keywords = channel_info_response_data['items'][0]['brandingSettings']['channel']['keywords']
except Exception as e:
    raise Exception(e)

3 个答案:

答案 0 :(得分:2)

您可以将所有作业都包装为

try:
    keywords = channel_info_response_data['items'][0]['brandingSettings']['channel']['keywords']
except KeyError as ignore:
    keywords = "default value"

,或者说,使用.has_key(...)。恕我直言,您最好采用第一种解决方案

答案 1 :(得分:2)

假设您有一个字典,则有两个选项可以处理关键不存在的情况:

1)获取具有默认值的密钥,例如

d = {}
val = d.get('k', 10)

val将为10,因为没有名为k的键

2)试用-

d = {}
try:
  val = d['k']
except KeyError:
  val = 10

这种方式更加灵活,因为您可以在except块中执行任何操作,如果您真的不在乎它,甚至可以使用pass语句忽略该错误。

答案 2 :(得分:1)

  

如何确保检查JSON输出

此时,您的“ JSON输出”只是一个普通的本地Python dict

  

为键分配一个变量之前?如果找不到密钥,那么我只想分配一个默认值

现在您知道自己有一个dict,浏览dict方法的官方文档应该会回答以下问题:

https://docs.python.org/3/library/stdtypes.html#dict.get

  

获取(键[,默认])

     

如果key在字典中,则返回key的值,否则返回默认值。如果未指定default,则默认为None,因此此方法永远不会引发KeyError。

所以一般情况是:

var = data.get(key, default)

现在,如果您在深层嵌套的字典/列表中可能缺少任何键或索引,则捕获KeyErrors和IndexErrors会更简单:

try:
   var = data[key1][index1][key2][index2][keyN]
except (KeyError, IndexError):
   var = default

请注意:您的代码段中包含重复的channel_info_response_data['items'][0]['statistics']channel_info_response_data['items'][0]['snippet']表达式。使用中间变量将使您的代码更具可读性,更易于维护,并且速度更快:

# always set a timeout if you don't want the program to hang forever
channel_info_response = requests.get(channel_info_url, timeout=30)
# always check the response status - having a response doesn't
# mean you got what you expected. Here we use the `raise_for_status()`
# shortcut which will raise an exception if we have anything else than
# a 200 OK.
channel_info_response.raise_for_status()

# requests knows how to deal with json:
channel_info_response_data = channel_info_response.json()

# we assume that the response MUST have `['items'][0]`,
# and that this item MUST have "statistics" and "snippets"
item = channel_info_response_data['items'][0]
stats = item["statistics"] 
snippet = item["snippet"]

no_of_videos = int(stats.get('videoCount', 0))
no_of_subscribers = int(stats.get('subscriberCount', 0))
no_of_views = int(stats.get('viewCount', 0))
avg_views = round(no_of_views / no_of_videos, 0)

try:
   photo = snippet['thumbnails']['high']['url']
except KeyError:
   photo = None

description = snippet.get('description', "")
start_date = snippet.get('publishedAt', None)
title = snippet.get('title', "")
try:
   keywords = item['brandingSettings']['channel']['keywords']
except KeyError
   keywords = ""

您可能还想了解字符串格式(污染字符串很容易出错并且几乎不可读),以及how to pass arguments to requests.get()