urllib2 POST 进度监控

10 投票
4 回答
5518 浏览
提问于 2025-04-16 17:12

我正在用urllib2把一个比较大的文件通过POST上传到服务器的脚本。我想显示一个进度指示器,来显示当前的上传进度。请问urllib2有没有什么方法或者回调可以让我监控上传的进度?我知道在下载的时候可以通过不断调用连接的read()方法来实现进度监控,但我没有看到write()方法,你只是把数据加到请求里。

4 个回答

1

requests 2.0.0 版本新增了流式上传的功能。这意味着你可以使用一个生成器来分批上传小块数据,并且在每次上传小块数据之间可以显示进度。

24

这是可能的,但你需要做一些事情:

  • 首先,你需要让urllib2这个模块“假装”能把文件句柄传递给httplib。为此,你可以给文件句柄加一个__len__属性,这样当你用len(data)去获取长度时,它会返回正确的大小,这个大小会用来填充Content-Length这个头信息。
  • 接着,你需要重写文件句柄的read()方法:当httplib调用read()时,你的回调函数会被触发,这样你就可以计算进度百分比并更新进度条。

这个方法可以用于任何类似文件的对象,但我这里用file来演示一下,看看它是如何处理从磁盘流式读取的大文件的:

import os, urllib2
from cStringIO import StringIO

class Progress(object):
    def __init__(self):
        self._seen = 0.0

    def update(self, total, size, name):
        self._seen += size
        pct = (self._seen / total) * 100.0
        print '%s progress: %.2f' % (name, pct)

class file_with_callback(file):
    def __init__(self, path, mode, callback, *args):
        file.__init__(self, path, mode)
        self.seek(0, os.SEEK_END)
        self._total = self.tell()
        self.seek(0)
        self._callback = callback
        self._args = args

    def __len__(self):
        return self._total

    def read(self, size):
        data = file.read(self, size)
        self._callback(self._total, len(data), *self._args)
        return data

path = 'large_file.txt'
progress = Progress()
stream = file_with_callback(path, 'rb', progress.update, path)
req = urllib2.Request(url, stream)
res = urllib2.urlopen(req)

输出:

large_file.txt progress: 0.68
large_file.txt progress: 1.36
large_file.txt progress: 2.04
large_file.txt progress: 2.72
large_file.txt progress: 3.40
...
large_file.txt progress: 99.20
large_file.txt progress: 99.87
large_file.txt progress: 100.00

撰写回答