我想编写代码将文件从一个站点传输到另一个站点。这可能是一个大文件,我想在不创建本地临时文件的情况下这样做。
我看到了使用mmap在Python上传大文件的技巧:" HTTP发布带有流媒体的大文件"但我真正需要的是一种将GET响应链接到创建POST。
之前有人这样做过吗?
答案 0 :(得分:3)
你不能,或者至少不应该。
urllib2
请求对象无法在运行时段将数据流式传输到它们中。而在另一个方向上,响应对象是类文件对象,理论上你可以read(8192)
而不是read()
,但对于大多数协议 - 包括HTTP - 它会经常或总是读取整个响应进入内存并从缓冲区中提供read(8192)
个调用,使其毫无意义。所以,你必须拦截请求,从中窃取套接字,并手动处理它,此时urllib2
正在阻碍你的工作,而不是它的帮助。
urllib2
使一些事情变得容易,有些事情比它们应该更难,有些事情几乎是不可能的;如果它不容易,请停止使用它。
一种解决方案是使用更高级别的第三方库。例如,requests
让你在中途(它可以很容易地从响应中流式传输,但只能在有限的情况下流式传输到响应中),而requests-toolbelt
可以让你获得剩余的响应。那里的方式(它添加了各种流上传方式)。
另一种解决方案是使用较低级别的库。在这里,你甚至不必离开stdlib。 httplib
强迫你一点一点地发送和接收事物,但这正是你想要的。在get请求中,您只需调用connect
和request
,然后在响应对象上重复调用read(8192)
。在帖子请求中,您拨打connect
,putrequest
,putheader
,endheaders
,然后重复send
来自get请求的每个缓冲区,然后{{1}当你完成时。
事实上,在Python 3.2 +的getresponse
(相当于2.x的http.client
)中,httplib
不一定是字符串,它可以是任何可迭代的或具有HTTPClient.request
和read
方法的任何类似文件的对象 ...其中包含一个响应对象。所以,就这么简单:
fileno
...当然,除了您可能想要制作合适的标题(您实际上可以使用import http.client
getconn = httplib.HTTPConnection('www.example.com')
getconn.request('GET', 'http://www.example.com/spam')
getresp = getconn.getresponse()
getconn = httplib.HTTPConnection('www.example.com')
getconn.request('POST', 'http://www.example.com/eggs', body=getresp)
getresp = getconn.getresponse()
,urllib.request
的3.x版本来构建urllib2
对象和不发送它...),并使用Request
将主机和端口从URL中拉出而不是硬编码,并且您想要耗尽或至少检查来自POST请求的响应,依此类推。但这显示了困难的部分,而且并不难。
不幸的是,我认为这不适用于2.x。
最后,如果您熟悉urlparse
,则至少有三个包装器(包括源代码分发附带的包装器)。我不确定是要将libcurl
调用为高级别还是低于libcurl
的级别,这有点像它自己奇怪的复杂轴。 :)
答案 1 :(得分:0)
urllib2可能过于简单。您可能想要查看pycurl。我知道它支持流媒体。