如何使用Python的urllib2下载分块数据

4 投票
3 回答
4397 浏览
提问于 2025-04-18 10:56

我正在尝试用Python 2从服务器下载一个大文件:

req = urllib2.Request("https://myserver/mylargefile.gz")
rsp = urllib2.urlopen(req)
data = rsp.read()

服务器使用“Transfer-Encoding: chunked”来发送数据,而我只收到了部分二进制数据,这些数据无法通过gunzip解压。

我需要多次调用read()吗?还是需要发起多个请求?如果是这样,它们应该怎么写?

注意:我想仅使用Python 2的标准库来解决这个问题,不想使用像urllib3或requests这样的额外库。这可能吗?

3 个回答

0

我也遇到过同样的问题。

我发现“Transfer-Encoding: chunked”这个东西经常和“Content-Encoding: gzip”一起出现。

所以也许我们可以获取到压缩的内容,然后解压缩它。

这样对我来说是有效的。

import urllib2
from StringIO import StringIO
import gzip

req = urllib2.Request(url)
req.add_header('Accept-encoding', 'gzip, deflate')
rsp = urllib2.urlopen(req)
if rsp.info().get('Content-Encoding') == 'gzip':
    buf = StringIO(rsp.read())
    f = gzip.GzipFile(fileobj=buf)
    data = f.read()
1

如果我没记错的话,下面这个方法之前对我有效:

data = ''
chunk = rsp.read()
while chunk:
    data += chunk
    chunk = rsp.read()

每次read操作都会读取一小块数据,所以要一直读取,直到没有更多的数据可以读取为止。现在还没有相关的文档支持这个说法……

1

来自Python文档关于urllib2.urlopen的内容:

有一点需要注意:如果你在使用read()方法时没有指定读取的大小,或者指定了一个负数,那么它可能不会一直读取到数据流的末尾;在一般情况下,没有好的方法来判断从一个套接字(socket)中是否已经读取了整个数据流。

所以,建议在一个循环中读取数据:

req = urllib2.Request("https://myserver/mylargefile.gz")
rsp = urllib2.urlopen(req)
data = rsp.read(8192)
while data:
   # .. Do Something ..
   data = rsp.read(8192)

撰写回答