Pydap调用open_url访问ORNL DAAC数据报UnicodeDecodeError如何解决?
问题根因
从报错堆栈可以定位到问题出在老版本pydap的dap.py模块逻辑:当服务端返回的HTTP响应头没有明确指定charset编码时,老版本pydap会强制将响应编码设为ascii,但ORNL DAAC的Thredds服务返回的响应要么是UTF-8编码的元数据,要么默认开启了gzip压缩(错误里的0x8b就是gzip文件的开头魔数),用ascii解码就会触发UnicodeDecodeError。
可行解决方案
方案1:升级pydap版本(优先推荐)
这个硬编码编码的问题是pydap的已知历史bug,新版本已经完成修复。直接执行命令升级pydap即可:
pip install --upgrade pydap
升级完成后直接运行原有代码即可正常请求ORNL的OPeNDAP接口。
方案2:手动修改pydap源码(无法升级版本时用)
如果你的环境有依赖冲突不能升级pydap,可以直接修改本地安装的pydap源码:
找到报错日志里的对应文件路径 ~/bc/lib/python3.8/site-packages/pydap/handlers/dap.py,将第56行的
r.charset = 'ascii'
修改为
r.charset = 'utf-8'
保存后重新运行代码即可生效。
方案3:请求时禁用gzip压缩(无需改源码/升级版本)
在创建认证session之后,给session增加禁用压缩的请求头,让服务端返回纯文本的未压缩响应,就可以避开ascii解码失败的问题:
from pydap.client import open_url from pydap.cas.urs import setup_session dataset_url = 'https://thredds.daac.ornl.gov/thredds/dodsC/ornldaac/1840/daymet_v4_daily_na_dayl_2009.nc' session = setup_session(username='****', password='****', check_url=dataset_url) # 新增下面这行,禁用gzip压缩 session.headers.update({'Accept-Encoding': 'identity'}) dataset = open_url(dataset_url, session=session)
额外注意事项
检查你的业务代码是否把创建好的带认证的session参数正确传给了open_url方法,从报错堆栈来看出错的代码行没有传入session参数,未通过EarthData认证的请求会收到服务端返回的错误响应,也可能触发解码异常。
内容的提问来源于stack exchange,提问作者mbexhrs3
相关产品推荐
相关产品推荐

