urllib.urlretrieve 自定义 header

urllib.urlretrieve with custom header

我正在尝试使用 urlretrieve 检索文件,同时添加自定义 header。

在检查 urllib.request 的代码源时,我意识到 urlopen 可以在参数中使用 Request object 而不仅仅是字符串,允许将 header 我想要。 但是,如果我尝试对 urlretrieve 执行相同的操作,我会得到另一个 post 中提到的

我最终做的是重写我自己的 urlretrieve,删除抛出错误的行(该行与我的用例无关)。

它工作正常 但我想知道是否有 better/cleaner 的方法,而不是重写我的拥有 urlretrieve。如果可以将自定义 header 传递给 urlopen,感觉应该可以对 urlretrieve?

做同样的事情

urllib.request.urlretrieve()urllib.request.urlopen() 里面使用(至少在 Python 3)。因此,您可以使用相同的方式来影响 urlopen.

的行为

当调用 urlopen(params) 时,它实际上首先查看特殊的全局变量 urllib.request._opener,如果它是 None,则 urlopen 将变量设置为默认值开瓶器否则它将保持原样。在下一步中,它将调用 urllib.request._opener.open(<urlopen_params>)(在接下来的部分中,我将 urllib.request._opener 仅称为 opener)。

opener.open() 包含不同协议的处理程序列表。当调用 opener.open() 时,它将执行以下操作:

  1. 从 URL urllib.request.Request object 创建(或者如果您直接提供 Request 它将直接使用它)。
  2. Request object 中提取协议(它从 URL 方案推导出来)。
  3. 根据协议,它将尝试查找并使用这些方法:
    • protocol_request(例如http_request)-它用于pre-process连接打开前的请求。
    • protocol_open - 实际创建与远程服务器的连接
    • protocol_response - 处理来自服务器的响应
    • 其他方法请看Python's documentation

对于您自己的开瓶器,您必须执行这 3 个步骤:

  1. 创建自己的处理程序
  2. 构建处理程序列表包含您的自定义处理程序(函数 urllib.request.build_opener
  3. 将新的 opener 安装到 urllib.request._opener(函数 urllib.request.install_opener

urllib.request.build_opener 创建包含您的自定义处理程序的开启器,并添加默认开启器,但您的自定义处理程序从中继承的处理程序除外。

所以要添加自定义 header 你可以这样写:

import urllib.request as req

class MyHTTP(req.HTTPHandler):
    def http_request(self, req):
        req.headers["MyHeader"] = "Content of my header"
        return super().http_request(req)

opener = req.build_opener(MyHTTP())
req.install_opener(opener)

从这一点开始,当您调用 urllib.request.urlretrieve() 或任何使用 urlopen() 的东西时,它将使用您的处理程序进行 HTTP 通信。当你想回到默认处理程序时,你可以调用:

import urllib.request as req   

req.install_opener(req.build_opener())

老实说,我不知道它是否是 better/cleaner 解决方案,但它使用 urllib.

中准备好的机制

我找到了一种方法,您只需添加几行额外的代码...

import urllib.request

opener = urllib.request.build_opener()
opener.addheaders = [('User-agent', 'Mozilla/5.0')]
urllib.request.install_opener(opener)
urllib.request.urlretrieve("type URL here", "path/file_name")

如果您想了解详细信息,可以参考 python 文档:https://docs.python.org/3/library/urllib.request.html