Geopy地理编码请求未正确捕获特定异常的问题排查
问题原因分析
- 异常归属层级不匹配:
ConnectTimeout(来自requests.exceptions)、MaxRetryError(来自urllib3.exceptions)属于HTTP请求层异常,并非geopy直接抛出的专属异常;GeocoderUnavailable虽属于geopy.exc,但当请求被Nominatim的频率限制直接阻断时,会优先触发底层HTTP异常,而非geopy封装的异常。 - 捕获顺序或范围错误:若仅捕获
geopy相关异常,会漏掉requests/urllib3抛出的底层错误,最终被通用Exception捕获。 - Nominatim请求限制触发:连续50-100次请求会触发Nominatim的频率限制(官方要求每秒最多1次请求),此时服务会拒绝连接,直接抛出HTTP层的重试超时或连接异常。
解决方案
1. 导入所有相关异常类
确保捕获链覆盖geopy、requests、urllib3的目标异常:
from geopy.geocoders import Nominatim from geopy.exc import GeocoderUnavailable, GeocoderTimedOut import requests from requests.exceptions import ConnectTimeout from urllib3.exceptions import MaxRetryError
2. 按「具体到通用」顺序捕获异常
先捕获最细分的异常,再逐步兜底,避免被上层异常提前拦截:
import time geolocator = Nominatim(user_agent="your_custom_user_agent") # 替换为合法的自定义User-Agent for idx in range(100): try: # 设置timeout参数,避免无限等待 location = geolocator.geocode("测试地址", timeout=15) if location: print(f"第{idx+1}次请求成功: {location.address}") # 遵守Nominatim频率限制,每次请求后休眠1秒 time.sleep(1) except GeocoderTimedOut as e: print(f"第{idx+1}次请求: 地理编码超时 - {str(e)}") except GeocoderUnavailable as e: print(f"第{idx+1}次请求: 地理编码服务不可用 - {str(e)}") except ConnectTimeout as e: print(f"第{idx+1}次请求: 连接超时 - {str(e)}") except MaxRetryError as e: print(f"第{idx+1}次请求: 请求重试次数耗尽 - {str(e)}") except requests.exceptions.ConnectionError as e: # 兜底捕获requests层所有连接类异常 print(f"第{idx+1}次请求: 连接错误 - {str(e)}") except Exception as e: # 最后捕获未覆盖的通用异常,记录详细信息 print(f"第{idx+1}次请求: 未知错误 - {str(e)},异常类型: {type(e).__name__}")
3. 遵守Nominatim使用规范
- 必须设置合法的
user_agent(不能用默认值),否则可能被拒绝服务 - 严格控制请求频率,每次请求后至少休眠1秒,避免触发限制
- 若需批量请求,可考虑使用Nominatim的批量查询接口或申请商业授权
内容的提问来源于stack exchange,提问作者Highnoon
相关产品推荐
相关产品推荐

