我正在尝试使用urlretrieve
检索文件,同时添加自定义标头。
在检查urllib.request
的代码源时,我意识到urlopen
可以在参数中使用Request
对象而不仅仅是字符串,允许放置我想要的标头。
但是如果我尝试对urlretrieve
做同样的事情,我会在另一篇文章中提到TypeError: expected string or bytes-like object。
我最终做的是重写我自己的urlretrieve,删除抛出错误的行(该行与我的用例无关)。
一切正常,但我想知道是否有更好/更清晰的方法,而不是重写我自己的urlretrieve
。如果可以将自定义标头传递给urlopen
,感觉应该可以对urlretrieve
执行相同操作吗?
答案 0 :(得分:25)
我找到了一种方法,你只需添加一些额外的代码......
let model = SCNScene(named: "Model.scnassets/model.scn")
let gun = SCNScene(named: "Model.scnassets/gun.dae")
model?.rootNode?.addChildNode(gun)
//fromFile is a custom extension
let animation = SCNAnimation.fromFile(named: "test_with_gun", inDirectory: "Model.scnassets/Animation")
if let anim = animation {
model.addAnimation(anim, forKey: anim.keyPath)
}
如果您想了解详细信息,可以参考python文档:https://docs.python.org/3/library/urllib.request.html
答案 1 :(得分:4)
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()
后,它将执行以下操作:
urllib.request.Request
对象创建(或者如果您直接提供Request
,则只会使用它。)Request
对象中提取协议(从URL方案推导出来)。protocol_request
(例如http_request
) - 用于在打开连接之前预处理请求。protocol_open
- 实际上与远程服务器建立连接protocol_response
- 处理来自服务器的响应对于你自己的开场白,你必须做这3个步骤:
urllib.request.build_opener
)urllib.request._opener
(函数urllib.request.install_opener
) urllib.request.build_opener
创建包含自定义处理程序的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
中的准备机制。