2013-06-24 166 views
6

我想用urllib3通过HTTP协议下载文件。 我已成功地做到这一点使用下面的代码:什么是使用urllib3下载文件的最佳方式

url = 'http://url_to_a_file' 
connection_pool = urllib3.PoolManager() 
resp = connection_pool.request('GET',url) 
f = open(filename, 'wb') 
f.write(resp.data) 
f.close() 
resp.release_conn() 

但我想知道什么是这样做的适当方式。 例如,它可以很好地处理大文件,并且如果没有该做什么来使这些代码更具有容错性和可扩展性。

注意。例如,使用urllib3库不是urllib2对我来说很重要,因为我希望我的代码是线程安全的。

回答

14

您的代码片段已关闭。值得一提的有两两件事:

  1. 如果您使用resp.data,它会消耗整个响应并返回连接(你没有需要手动resp.release_conn())。如果你把数据保存在内存中很酷,这很好。

  2. 您可以使用resp.read(amt)这将传输响应,但连接将需要通过resp.release_conn()返回。

这看起来是这样的......

import urllib3 
http = urllib3.PoolManager() 
r = http.request('GET', url, preload_content=False) 

with open(path, 'wb') as out: 
    while True: 
     data = r.read(chunk_size) 
     if not data: 
      break 
     out.write(data) 

r.release_conn() 

该文档可能会有点欠缺这种方案。如果有人有兴趣制作pull-request to improve the urllib3 documentation,那将不胜感激。命名变量:)

+0

那么。谢谢你的回答。 –

+0

还有一个问题。如果我添加'r = http.request('POST',url)'',它会与POST方法一起工作吗? –

+0

@ running.t错误,这是我的代码中的错误。你是对的,该方法应该先行,你的代码段将起作用。 (更新了我的答案。) – shazow

-2

附加preload_content否则你最终将下载全部内容

http.request('GET', url, preload_content=False) 
+0

@ 2Dee:你能否告诉我这里有什么问题,这样我就可以纠正自己 – giridhar

+1

我认为,虽然你的回答可能是正确的(我对urllib3不熟悉),但似乎没有完全解决问题。也就是说,我没有把你的答案投下来,如果你看到我的名字出现在帖子下,那只是因为我编辑了你的答案,所以代码将被正确格式化。希望这可以让你更清楚;) – 2Dee

2

最正确的方式做到这一点可能是获取表示HTTP响应一个类似文件的对象,并将其复制使用shutil.copyfileobj到一个真实的文件如下:

url = 'http://url_to_a_file' 
c = urllib3.PoolManager() 

with c.request('GET',url, preload_content=False) as resp, open(filename, 'wb') as out_file: 
    shutil.copyfileobj(resp, out_file) 

resp.release_conn()  # not 100% sure this is required though 
相关问题