内部的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()
被调用时,它将执行以下操作:
- 从 URL
urllib.request.Request
对象创建(或者如果您直接提供Request
它只会使用它)。
- 从
Request
对象中提取协议(它从 URL 方案推导出来)。
- 根据协议,它将尝试查找并使用这些方法:
protocol_request
(例如http_request
) - 它用于在打开连接之前预处理请求。
protocol_open
- 实际上创建与远程服务器的连接
protocol_response
- 处理来自服务器的响应
- 对于其他方法,请查看Python 的文档
对于您自己的开瓶器,您必须执行以下 3 个步骤:
- 创建自己的处理程序
- 处理程序的构建列表包含您的自定义处理程序(函数
urllib.request.build_opener
)
- 将新的开瓶器安装到
urllib.request._opener
(功能urllib.request.install_opener
)
创建包含您的自定义处理程序的urllib.request.build_opener
开启程序并添加默认开启程序,但您的自定义处理程序继承自处理程序。
因此,要添加自定义标头,您可以编写如下内容:
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())
老实说,我不知道它是否比您的解决方案更好/更清洁,但它在urllib
.