You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Requests中Try-Except处理KeyError的异常问题排查

问题分析与解决办法

咱们先拆解你遇到的两个核心问题:触发KeyError: 'row'的根本原因,以及错误使用try-except导致正常球员被跳过的逻辑问题。

为什么会触发KeyError: 'row'?

MLB的PECOTA击球预测API并非对所有球员都返回有效数据:

  • 部分球员(比如投手、新秀、数据不足的边缘球员)没有对应的击球预测结果,此时API返回的proj_pecota_batting.queryResults里不存在row字段,或者totalSize字段值为0(表示无数据)。
  • 原脚本直接硬编码提取['row'],一旦遇到这种无数据的情况,就会抛出KeyError中断脚本执行。

为什么添加try-except后会跳过正常球员?

你的try-except逻辑完全颠倒了!看你的代码片段:

try:
    info1 = req2.json()['proj_pecota_batting']['queryResults']['row']
except(KeyError):
    # 这里居然还去访问info1的字段?!
    hr = info1['hr']
    ...
    print(...)

当获取info1成功时(正常有数据的球员),try块执行完就直接跳过了except块的打印逻辑;只有触发KeyError时(无数据的球员)才会进入except块,但此时info1根本没被定义,会抛出新的NameError,导致该球员被跳过,而正常球员因为没执行打印代码,看起来也被“跳过”了——这完全是逻辑搞反了!

正确的解决办法

1. 修正try-except核心逻辑

把正常获取数据、提取字段、打印的代码都放在try块里,except块只负责处理异常情况(比如记录跳过的球员):

# Use playerId string to run through PECOTA BATTING PROJECTIONS
req2 = requests.get(f"http://lookup-service-prod.mlb.com/json/named.proj_pecota_batting.bam?season='2018'&player_id='{playerId}'")
try:
    query_result = req2.json()['proj_pecota_batting']['queryResults']
    # 先判断是否有有效数据,提前规避KeyError
    if int(query_result['totalSize']) == 0:
        print(f"跳过无PECOTA数据的球员: {player}")
        continue
    # 注意:API返回的row可能是单个字典(单条数据)或列表(多条数据),统一处理成字典
    info1 = query_result['row']
    if isinstance(info1, list):
        info1 = info1[0]
    # 提取字段
    hr = info1['hr']
    sac = info1['sac']
    rbi = info1['rbi']
    tb = info1['tb']
    slg = info1['slg']
    bavg = info1['avg']
    bb = info1['bb']
    ops = info1['ops']
    hbp = info1['hbp']
    games = info1['g']
    d = info1['d']
    e = info1['e']
    so = info1['so']
    sf = info1['sf']
    tpa = info1['tpa']
    h = info1['h']
    cs = info1['cs']
    obp = info1['obp']
    t = info1['t']
    s = info1['s']
    r = info1['r']
    sb = info1['sb']
    sbpct = info1['sbpct']
    ab = info1['ab']
    ibb = info1['ibb']
    print(player,team,hr,sac,rbi,tb,slg,bavg,bb,ops,hbp,games,d,e,so,sf,tpa,h,cs,obp,t,s,r,sb,sbpct,ab,ibb)
except KeyError as e:
    print(f"球员 {player} 数据结构异常,缺失字段: {e}")
except Exception as e:
    # 捕获其他意外错误(比如网络超时、JSON解析失败)
    print(f"处理球员 {player} 时出错: {str(e)}")

2. 额外优化点

  • 用f-string拼接URL,比字符串相加更清晰,也更不容易出错。
  • 提前检查totalSize字段,从源头避免KeyError的触发。
  • 处理row的多格式问题:部分球员的返回是单个字典,部分是包含一个字典的列表,统一转成字典后再提取字段。
  • 捕获通用Exception,避免其他非预期错误中断整个脚本的运行。

3. 关于“运行约9次后报错”的说明

这只是巧合——前9个遍历到的球员刚好都有PECOTA数据,第10个没有,所以触发了KeyError。这个次数不是固定的,完全取决于你遍历球员的顺序。

内容的提问来源于stack exchange,提问作者Michael T Johnson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:26:34