Python调用SendGrid API时如何处理KeyError异常保障日报运行?
处理SendGrid API空统计数据的异常问题
嘿,我明白你的困扰!这个KeyError确实是因为当三天前没有可用数据时,API返回的stats是个空列表,导致后续处理DataFrame的时候找不到name列。咱们可以通过提前检查数据是否为空和异常捕获两种方式来解决,让程序能稳定运行不中断。
方案1:提前检查返回的统计数据是否为空
在循环处理每个品牌的API响应时,先判断stats列表有没有内容,如果是空的就直接跳过当前品牌的处理,避免后续报错。修改后的代码如下:
import pandas as pd import json import datetime import http.client threedaysago = datetime.date.fromordinal(datetime.date.today().toordinal()-3).strftime("%F") conn = http.client.HTTPSConnection("api.sendgrid.com") payload = "{}" keys = { # "CF" : "SG.UdhzjmjYR**.-", } df = [] # Create new Dataframe for name, value in keys.items(): headers = { 'authorization': "Bearer " + value } conn.request("GET", "/v3/categories/stats/sums?aggregated_by=&start_date={d}&end_date={d}".format(d=threedaysago), payload, headers) res = conn.getresponse() data = res.read() print(data.decode("utf-8")) d = json.loads(data.decode("utf-8")) c = d['stats'] # 新增:检查stats是否为空,为空则跳过当前品牌 if not c: print(f"品牌 {name} 在 {threedaysago} 没有统计数据,跳过处理") continue df.append(c) # 新增:检查是否有有效数据可以处理 if df: # Load data row into df #1 df = pd.DataFrame(df[0]) df_new = df[['name']] df_new.rename(columns={'name':'Category'}, inplace=True) df_metric =pd.DataFrame(list(df['metrics'].values)) sendgrid = pd.concat([df_new, df_metric], axis=1, sort=False) sendgrid.set_index('Category', inplace = True) sendgrid.insert(0, 'Date', threedaysago) sendgrid.insert(1,'BrandId',99) sendgrid.rename(columns={ 'blocks':'Blocks', 'bounce_drops' : 'BounceDrops', 'bounces': 'Bounces', 'clicks':'Clicks', 'deferred':'Deferred', 'delivered':'Delivered', 'invalid_emails': 'InvalidEmails', 'opens':'Opens', 'processed':'Processed', 'requests':'Requests', 'spam_report_drops' : 'SpamReportDrops', 'spam_reports' : 'SpamReports', 'unique_clicks' : 'UniqueClicks', 'unique_opens' : 'UniqueOpens', 'unsubscribe_drops' : 'UnsubscribeDrops', 'unsubscribes': 'Unsubscribes' }, inplace=True) # 这里可以添加保存或发送日报的代码 else: print(f"所有品牌在 {threedaysago} 都没有统计数据,本次日报无内容") # 可以选择生成空报表或者发送提示消息
方案2:用try-except捕获异常
如果担心还有其他可能的KeyError情况,可以用try-except块包裹DataFrame处理逻辑,这样即使出现意外错误,程序也不会中断:
# ... 前面的循环代码和方案1一样 ... try: df = pd.DataFrame(df[0]) df_new = df[['name']] df_new.rename(columns={'name':'Category'}, inplace=True) df_metric =pd.DataFrame(list(df['metrics'].values)) sendgrid = pd.concat([df_new, df_metric], axis=1, sort=False) sendgrid.set_index('Category', inplace = True) sendgrid.insert(0, 'Date', threedaysago) sendgrid.insert(1,'BrandId',99) sendgrid.rename(columns={ 'blocks':'Blocks', 'bounce_drops' : 'BounceDrops', # ... 其他列名映射 ... }, inplace=True) except KeyError as e: print(f"处理日报数据时出错:{e},大概率是因为 {threedaysago} 没有可用统计数据") # 这里可以执行备选逻辑,比如生成空的日报模板
为什么这样有效?
当API返回"stats":[]时,c就是空列表,我们通过if not c直接跳过后续的数据处理步骤,避免了创建空DataFrame后去查找不存在的name列。而try-except则是兜底方案,能捕获任何KeyError异常,让程序继续运行。
内容的提问来源于stack exchange,提问作者user12384956




