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

如何用requests实现urllib中HTTPPasswordMgrWithDefaultRealm的认证下载?

问题描述

已通过urllib实现NASA MODIS HDF文件的认证下载(示例文件来自https://e4ftl01.cr.usgs.gov/MOLT/MOD09GQ.061/2000.05.14),urllib实现代码如下:

url = "https://e4ftl01.cr.usgs.gov/MOLT/MOD09GQ.061/2000.05.14/MOD09GQ.A2000135.h20v02.061.2020042041314.hdf"

password_manager = urllib.request.HTTPPasswordMgrWithDefaultRealm()
password_manager.add_password(None, "https://urs.earthdata.nasa.gov", username, password)
CJ = cookielib.CookieJar()

opener = urllib.request.build_opener(
    urllib.request.HTTPBasicAuthHandler(password_manager),
    urllib.request.HTTPCookieProcessor(CJ))
urllib.request.install_opener(opener)

req = urllib.request.Request(url)
with urllib.request.urlopen(req) as resp:
    with open("im.hdf", "wb") as _fb:
        _fb.write(resp.read())

尝试改用requests实现时,三种基础认证方式均返回401错误:

  • 会话中传递auth元组:
with requests.Session() as s:
    _auth = (username, password)
    with s.get(url, auth=_auth) as resp:
        print(resp.status_code)
        print(resp.headers)
  • 使用HTTPBasicAuth:
with requests.Session() as s:
    _auth = HTTPBasicAuth(username, password)
    with s.get(url, auth=_auth) as resp:
        print(resp.status_code)
        print(resp.headers)
  • 为会话设置auth属性:
with requests.Session() as s:
    s.auth = (username, password)
    with s.get(url) as resp:
        print(resp.status_code)
        print(resp.headers)

错误响应头包含WWW-Authenticate: Basic realm="Please enter your Earthdata Login credentials. If you do not have a Earthdata Login, create one at https://urs.earthdata.nasa.gov//users/new",响应内容为b'HTTP Basic: Access denied.'。

环境:Python 3.8.10(Linux WSL)、requests2.28.1、requests-oauthlib1.3.1

解决方案

Earthdata的认证机制是跨域名Cookie认证:文件服务器会重定向到URS(Earthdata Login服务器)完成认证,认证通过后URS会设置会话Cookie,后续访问文件服务器时需要携带该Cookie。直接给文件URL附加Basic Auth会失败,因为文件服务器不处理认证逻辑,只会引导到URS。

以下是等效的requests实现代码:

import requests

# 目标文件URL
file_url = "https://e4ftl01.cr.usgs.gov/MOLT/MOD09GQ.061/2000.05.14/MOD09GQ.A2000135.h20v02.061.2020042041314.hdf"
# 替换为你的Earthdata账号信息
username = "your_earthdata_username"
password = "your_earthdata_password"

# 创建会话对象,自动管理Cookie
session = requests.Session()

# 先向URS服务器发起认证,获取认证Cookie
session.auth = (username, password)
# 发送HEAD请求触发认证流程,会话会自动保存返回的Cookie
session.head("https://urs.earthdata.nasa.gov")

# 使用带认证Cookie的会话下载文件,stream=True适合大文件
with session.get(file_url, stream=True) as response:
    # 检查请求是否成功,失败则抛出异常
    response.raise_for_status()
    # 分块写入文件,避免内存溢出
    with open("im.hdf", "wb") as f:
        for chunk in response.iter_content(chunk_size=8192):
            f.write(chunk)

核心要点:

  • 必须先向https://urs.earthdata.nasa.gov发起认证,让会话保存认证后的Cookie,才能访问文件服务器。
  • stream=True和iter_content用于分块下载大文件,避免一次性加载整个文件到内存。
  • 会话对象会自动处理重定向和Cookie的保存/携带,无需手动管理。

内容的提问来源于stack exchange,提问作者GionniD

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 16:37:45