如何捕获已被Python第三方模块捕获的PySocks异常?
捕获被包装的PySocks代理异常
解决思路
第三方库(urllib3、requests)会将PySocks的ProxyError子类重新包装成上层异常,但Python异常会保留原始异常的上下文链。我们可以通过遍历最终抛出的requests.exceptions.ConnectionError的异常链,找到底层的PySocks异常,无需修改第三方库源码。
具体实现
基础版代码
import requests import socks try: # 替换为你的请求逻辑 response = requests.get( "https://example.com", proxies={"https": "socks4://your-proxy-address:port"} ) except requests.exceptions.ConnectionError as top_exc: # 遍历异常上下文链,查找PySocks的ProxyError current_exception = top_exc while current_exception is not None: if isinstance(current_exception, socks.ProxyError): # 这里处理PySocks代理错误 print(f"捕获到PySocks代理异常: {str(current_exception)}") # 可添加自定义逻辑:比如重试代理、记录日志等 break # 切换到下一层上下文异常 current_exception = current_exception.__context__ else: # 如果未找到PySocks异常,重新抛出原始连接错误 raise
通用辅助函数
如果需要多次使用,可封装辅助函数简化异常链遍历:
import requests import socks def find_target_exception(exception_chain, target_exception_type): """遍历异常链,查找目标类型的异常""" current_exc = exception_chain while current_exc is not None: if isinstance(current_exc, target_exception_type): return current_exc # 优先检查默认上下文__context__,再检查显式关联的__cause__ current_exc = current_exc.__context__ or current_exc.__cause__ return None # 使用示例 try: requests.get("https://example.com", proxies={"https": "socks4://your-proxy:port"}) except requests.exceptions.ConnectionError as e: proxy_error = find_target_exception(e, socks.ProxyError) if proxy_error: print(f"处理代理错误: {proxy_error}") # 自定义处理逻辑 else: # 非代理导致的连接错误,重新抛出 raise
原理说明
- 当Python在
except块中重新抛出新异常且未使用raise ... from时,原始异常会被保存在新异常的__context__属性中;若使用raise ... from显式关联,则保存在__cause__属性中。 - urllib3包装PySocks异常时使用默认上下文传递,因此通过遍历
__context__即可找到底层的ProxyError或其子类(如ProxyConnectionError)。
内容的提问来源于stack exchange,提问作者Xiddoc
相关产品推荐
相关产品推荐

