python:将大文件下载到本地路径并设置自定义HTTP头

Python: Downloading a large file to a local path and setting custom http headers

我想从一个HTTP URL下载一个文件到一个本地文件。文件足够大,我想下载并保存它的块,而不是将整个文件作为一个巨大的字符串保存在read()write()

urllib.urlretrieve的接口本质上是我想要的。但是,在通过urllib.urlretrieve下载时,我看不到设置请求头的方法,这是我需要做的。

如果我使用urllib2,我可以通过其Request对象设置请求头。但是,我在urllib2中没有看到将文件直接下载到磁盘路径(如urlretrieve)的API。相反,我必须使用一个循环以块的形式迭代返回的数据,自己将它们写入一个文件,并在完成时进行检查。

构建一个类似于urllib.urlretrieve但允许传入请求头的函数的最佳方法是什么?


使用urllib2编写自己的函数有什么坏处?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import os
import sys
import urllib2

def urlretrieve(urlfile, fpath):
    chunk = 4096
    f = open(fpath,"w")
    while 1:
        data = urlfile.read(chunk)
        if not data:
            print"done."
            break
        f.write(data)
        print"Read %s bytes"%len(data)

并使用请求对象设置头

1
2
3
request = urllib2.Request("http://www.google.com")
request.add_header('User-agent', 'Chrome XXX')
urlretrieve(urllib2.urlopen(request),"/tmp/del.html")

如果您想使用urllib和urlretrieve,那么子类urllib.URLopener并使用它的addheader()方法来调整报头(即:addheader('Accept', 'sound/basic'),它是我从urlib.addheader的docstring中提取的)。

要安装供urllib使用的urlopener,请参阅文档的urllib.u urlopener部分中的示例(注意下划线):

1
2
3
4
5
6
import urllib

class MyURLopener(urllib.URLopener):
    pass # your override here, perhaps to __init__

urllib._urlopener = MyURLopener

然而,你会很高兴听到你对问题评论的评论,从read()中读取一个空字符串确实是停止的信号。例如,这就是UrlRetrieve处理何时停止的方式。TCP/IP和套接字抽象读取过程,阻止等待其他数据,除非另一端的连接是EOF并关闭,在这种情况下,从连接读取()将返回空字符串。空字符串表示没有数据流入…您不必担心有序的数据包重新组装,因为这些都是为您处理的。如果这是你对Urllib2的关心,我想你可以安全地使用它。