带有自定义标题的urllib.urlretrieve

时间:2017-07-21 23:11:41

标签: python-3.x urllib urlretrieve

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

在检查urllib.request的代码源时,我意识到urlopen可以在参数中使用Request对象而不仅仅是字符串,允许放置我想要的标头。 但是如果我尝试对urlretrieve做同样的事情,我会在另一篇文章中提到TypeError: expected string or bytes-like object

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

一切正常,但我想知道是否有更好/更清晰的方法,而不是重写我自己的urlretrieve。如果可以将自定义标头传递给urlopen,感觉应该可以对urlretrieve执行相同操作吗?

2 个答案:

答案 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()后,它将执行以下操作:

  1. 从网址urllib.request.Request对象创建(或者如果您直接提供Request,则只会使用它。)
  2. Request对象中提取协议(从URL方案推导出来)。
  3. 根据协议,它将尝试查找并使用这些方法:
    • protocol_request(例如http_request) - 用于在打开连接之前预处理请求。
    • protocol_open - 实际上与远程服务器建立连接
    • protocol_response - 处理来自服务器的响应
    • 其他方法请查看Python's documentation
  4. 对于你自己的开场白,你必须做这3个步骤:

    1. 创建自己的处理程序
    2. 构建处理程序列表包含自定义处理程序(函数urllib.request.build_opener
    3. 将新的开场白安装到urllib.request._opener(函数urllib.request.install_opener
    4. 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中的准备机制。