[Python] 使用urllib模块下载文件并显示进度

我们都知道,python2和python3有很多库都不兼容,urllib就是其中之一,这真是恼火之极。不过,有需求就有发展,像six这类神奇的模块就诞生了,它的主要作用就是在python2和python3之间提供一个统一的接口,让你的程序同时可以支持python2和python3。

six.moves.urllib库就是python2和python3的urllib库的统一。

我目前用到urllib库的作用就是从网络上下载文件,比如下载MNIST数据集,这涉及到urllib.request.urlretrieve。

从python3的urllib的文档上看,urlretrieve是从python2遗留下来的接口,今后可能会被废止,但是我找了好久,都没找到python3中的新的替代接口,所以还是继续学习它吧。

urlretrieve的函数原型:

1
urllib.request.urlretrieve(url, filename=None, reporthook=None, data=None)

该函数的作用是从url所指向的地址处下载文件到本地。各参数的作用:

  • url:需要下载的网页的url
  • filename:如果指定此参数,则会将该url保存到这个参数指定的文件中
  • reporthook:报告下载进度的钩子函数(回调函数)
  • data:额,没看到有任何作用

此外,该函数会返回一个元组(filename, header):

  • filename: 下载到本地的文件的文件名
  • header: 一般不用关心

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
import sys
from six.moves import urllib

DOWNLOAD_URL = 'http://yann.lecun.com/exdb/mnist/'
filename = 'train-labels-idx1-ubyte.gz'

def _hook_func(num, block_size, total_size):
precent = min(100, 100.0*num*block_size/total_size)
sys.stdout.write('Downloading progress %.2f%%\r' % (precent))
sys.stdout.flush()

urllib.request.urlretrieve(DOWNLOAD_URL + filename, filename, _hook_func)
print()

特别说明,如果下载意外中断,则该函数会抛出异常。