Python中使用for循环处理grequests响应时遭遇JSONDecodeError的技术求助
解决grequests遍历响应时的JSONDecodeError及赋值错误问题
看起来你碰到了两个棘手的小问题:一是部分响应解析JSON时失败,二是循环里的赋值逻辑完全不符合预期。咱们一步步拆解解决:
问题1:JSONDecodeError的根源
grequests.map(rs)返回的响应列表里,大概率存在请求失败的情况——比如某个精灵名称拼写有误,导致API返回404错误;或是网络波动让响应内容为空。这时候调用x.json()自然会报错,因为空内容或者错误页面根本不是有效的JSON格式。
你单独测试s[0].json()能成功,只是刚好第一个请求运气好成功了,但其他请求说不定早就"翻车"了。
问题2:循环赋值的逻辑漏洞
你循环里写的null_data.loc[null_data['name'] == i.capitalize(), 'weight_kg'] = peso里,i是外层for i in null_data['name']循环的最后一个值,不是当前响应对应的精灵名称。最终结果就是所有体重数据都会被赋值给最后一个精灵,完全偏离了你的初衷。
修复后的完整代码
我们需要做这几件事:把请求和对应的精灵名称绑定、先验证响应有效性再解析、捕获异常避免循环中断。
import requests import json import grequests # 准备请求时同时保存对应的精灵名称,避免后续混淆 requests_list = [] pokemon_names = [] for name in null_data['name']: url = f'https://pokeapi.co/api/v2/pokemon/{name.lower()}' requests_list.append(grequests.get(url)) pokemon_names.append(name) # 把每个请求和名称一一对应 # 批量发送请求并获取响应 responses = grequests.map(requests_list) # 遍历响应和对应的精灵名称,一一处理 for resp, name in zip(responses, pokemon_names): # 先判断请求是否有效:响应存在且状态码为200 if resp and resp.status_code == 200: try: js_data = resp.json() weight_kg = js_data['weight'] / 10 # 用当前的精灵名称定位DataFrame行,完成赋值 null_data.loc[null_data['name'] == name, 'weight_kg'] = weight_kg except (KeyError, json.JSONDecodeError) as e: print(f"处理精灵{name}时出错: {str(e)}") else: # 打印失败信息,方便排查问题 status_code = resp.status_code if resp else "无响应" print(f"请求精灵{name}失败,状态码: {status_code}")
核心改进点
- 请求与名称绑定:用
zip(responses, pokemon_names)把每个响应和对应的精灵名称绑定,彻底解决赋值错位的问题 - 响应有效性检查:先判断
resp是否存在,再检查状态码是否为200,避免解析无效响应 - 异常捕获机制:用
try-except捕获JSON解析和字段提取时的异常,保证一个请求失败不会导致整个循环终止 - 调试友好:打印错误信息,能快速定位是哪个精灵的请求出了问题
这样修改后,既能避开JSON解析报错,也能精准把每个精灵的体重数据对应到DataFrame的正确行里。
内容的提问来源于stack exchange,提问作者Sotovision4K




