Python中except块未捕获全部错误:NIST API获取CVSS分数异常
问题:调用NIST API计算CVSS分数时异常无法捕获
我正在开发一个通过CVEID为已发现漏洞计算CVSS分数的项目,调用NIST的REST API时频繁因响应格式问题报错。为了调试方便,我想忽略所有错误并排查失败的请求,用了try-except块处理异常,但还是有错误抓不到。下面是我的代码(后来发现是低级错误):
from openpyxl import load_workbook from urllib import request import json from time import sleep basecolumn = 13 baseline = 1 wb = load_workbook('vulnerabilities.xlsm',keep_vba=True) ws = wb['CISA Last CVE'] wb.save('Test2.xlsm') CVEID = "temp" lineCounter = 0 while CVEID is not None: # While they are vulnerabilities to scan lineCounter +=1 line = baseline+lineCounter CVEID = ws.cell(row=line,column=1).value if ws.cell(row=line,column=basecolumn).value is None: # Checks if CVE was already scanned previously with request.urlopen("https://services.nvd.nist.gov/rest/json/cve/1.0/"+str(CVEID)) as response: print(str(CVEID)) html = response.read() responseCVE = html.decode('utf8').replace("'", '"') # Converts to JSON responseJSON = json.loads(responseCVE) try: exploitability = responseJSON['result']['CVE_Items'][0]['impact']['baseMetricV2']['exploitabilityScore'] impact = responseJSON['result']['CVE_Items'][0]['impact']['baseMetricV2']['impactScore'] except json.decoder.JSONDecodeError: print("first try not working") exploitability = responseJSON['result']['CVE_Items'][0]['impact']['baseMetricV3']['exploitabilityScore'] impact = responseJSON['result']['CVE_Items'][0]['impact']['baseMetricV3']['impactScore'] except: print("Mistery error") #print(exploitability) #print(impact) ws.cell(row=line,column=basecolumn).value = exploitability ws.cell(row=line, column=basecolumn+1).value = impact sleep(10) else : print("Already scanned " + str(CVEID) +" vulnerability") print(ws.cell(row=line, column=basecolumn).value) wb.save('Test2.xlsm')
问题根源
你的代码里有几个明显的低级错误,导致异常无法被捕获:
- try-except范围太小:API请求、JSON解析这些最容易抛出异常的操作都在try块外面,比如
request.urlopen可能抛出网络错误,json.loads可能抛出解析错误,这些都没被你的try-except覆盖,自然会直接崩溃。 - 多余的单引号替换:NIST API返回的是标准JSON格式,你用
replace("'", '"')反而会破坏合法的JSON结构(比如字符串里的单引号会被替换),直接导致json.loads报错。 - 异常捕获逻辑错误:第一个except捕获的
JSONDecodeError只会在json.loads时抛出,但这行代码在try块外面,所以这个分支永远不会触发;而取值时如果遇到键不存在(比如没有baseMetricV2),会抛出KeyError,虽然最后有个万能except,但前面的错误已经让程序终止了。
修正后的代码
from openpyxl import load_workbook from urllib import request, error import json from time import sleep basecolumn = 13 baseline = 1 wb = load_workbook('vulnerabilities.xlsm', keep_vba=True) ws = wb['CISA Last CVE'] wb.save('Test2.xlsm') lineCounter = 0 while True: lineCounter += 1 line = baseline + lineCounter CVEID = ws.cell(row=line, column=1).value # 当CVEID为空时退出循环 if not CVEID: break if ws.cell(row=line, column=basecolumn).value is None: print(f"Processing {CVEID}") exploitability = None impact = None try: # 拼接URL时先检查CVEID url = f"https://services.nvd.nist.gov/rest/json/cve/1.0/{CVEID}" with request.urlopen(url) as response: # 直接读取JSON,无需手动解码替换 responseJSON = json.load(response) # 先尝试取V2的分数 if 'result' in responseJSON and 'CVE_Items' in responseJSON['result'] and len(responseJSON['result']['CVE_Items']) > 0: cve_item = responseJSON['result']['CVE_Items'][0] if 'impact' in cve_item: # 优先V2 if 'baseMetricV2' in cve_item['impact']: metric = cve_item['impact']['baseMetricV2'] exploitability = metric.get('exploitabilityScore') impact = metric.get('impactScore') # V2不存在再试V3 elif 'baseMetricV3' in cve_item['impact']: metric = cve_item['impact']['baseMetricV3'] exploitability = metric.get('exploitabilityScore') impact = metric.get('impactScore') except error.URLError as e: print(f"Network error for {CVEID}: {str(e)}") except json.JSONDecodeError as e: print(f"JSON parse error for {CVEID}: {str(e)}") except (KeyError, IndexError) as e: print(f"Missing data in response for {CVEID}: {str(e)}") except Exception as e: print(f"Unexpected error for {CVEID}: {str(e)}") # 只有成功获取到分数才写入表格 if exploitability is not None and impact is not None: ws.cell(row=line, column=basecolumn).value = exploitability ws.cell(row=line, column=basecolumn+1).value = impact sleep(10) else: print(f"Already scanned {CVEID} vulnerability") print(ws.cell(row=line, column=basecolumn).value) wb.save('Test2.xlsm')
关键修改点
- 把API请求、JSON解析、分数取值整个流程都放进try块,确保所有异常都能被捕获
- 去掉了破坏JSON格式的
replace("'", '"'),直接用json.load(response)读取响应 - 明确捕获具体的异常类型(网络错误、解析错误、键/索引错误),方便调试
- 先检查JSON结构中的键是否存在,避免直接取值抛出KeyError,逻辑更健壮
- 优化循环条件,当CVEID为空时直接退出,避免无效循环
- 只有成功获取到分数才写入表格,避免写入空值或错误值
内容的提问来源于stack exchange,提问作者Wosiru
相关产品推荐
相关产品推荐

