urllib2 POST 进度监控

发布于 2024-11-05 09:29:02 字数 164 浏览 1 评论 0原文

我正在通过 POST 使用 urllib2 将一个相当大的文件上传到服务器端脚本。我想显示一个进度指示器,显示当前上传进度。 urllib2 是否提供了一个钩子或回调来让我监控上传进度?我知道您可以通过连续调用连接的 read() 方法来进行下载,但我没有看到 write() 方法,您只需将数据添加到请求中即可。

I'm uploading a fairly large file with urllib2 to a server-side script via POST. I want to display a progress indicator that shows the current upload progress. Is there a hook or a callback provided by urllib2 that allows me to monitor upload progress? I know that you can do it with download using successive calls to the connection's read() method, but I don't see a write() method, you just add data to the request.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

淡莣 2024-11-12 09:29:02

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

  • 通过附加一个 __len__ 属性来伪造 urllib2 子系统,将文件句柄传递给 httplib,该属性使得 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

It is possible but you need to do a few things:

  • Fake out the urllib2 subsystem into passing a file handle down to httplib by attaching a __len__ attribute which makes len(data) return the correct size, used to populate the Content-Length header.
  • Override the read() method on your file handle: as httplib calls read() your callback will be invoked, letting you calculate the percentage and update your progress bar.

This could work with any file-like object, but I've wrapped file to show how it could work with a really large file streamed from disk:

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)

Output:

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
陌上芳菲 2024-11-12 09:29:02

requests 2.0.0 具有流式上传。这意味着您可以使用生成器来生成微小的块并打印块之间的进度。

requests 2.0.0 has streaming uploads. This means you can use a generator to yield tiny chunks and print the progress between chunks.

羁客 2024-11-12 09:29:02

我认为这是不可能的,但是 pycurl 确实有上传/下载进度回调可以使用。

I don't think this is possible, but pycurl does have upload/download progress callbacks you can use.

z祗昰~ 2024-11-12 09:29:02

海报 支持此功能

import json
import os
import sys
import urllib2

from poster.encode import multipart_encode
from poster.streaminghttp import register_openers

def _upload_progress(param, current, total):
    sys.stdout.write(
        "\r{} - {:.0f}%                "
        .format(param.name,
                (float(current) / float(total)) * 100.0))
    sys.stdout.flush()

def upload(request_resource, large_file_path):
    register_openers()
    with open(large_file_path, 'r') as large_file:
        request_data, request_headers = multipart_encode(
            [('file', largs_file)],
            cb=_upload_progress)

        request_headers.update({
            'X-HockeyAppToken': 'we use this for hockeyapp upload'
        })

        upload_request = urllib2.Request(request_resource,
                                         request_data, 
                                         request_headers)
        upload_connection = urllib2.urlopen(upload_request)
        upload_response = json.load(upload_connection)
    print "Done"

poster supports this

import json
import os
import sys
import urllib2

from poster.encode import multipart_encode
from poster.streaminghttp import register_openers

def _upload_progress(param, current, total):
    sys.stdout.write(
        "\r{} - {:.0f}%                "
        .format(param.name,
                (float(current) / float(total)) * 100.0))
    sys.stdout.flush()

def upload(request_resource, large_file_path):
    register_openers()
    with open(large_file_path, 'r') as large_file:
        request_data, request_headers = multipart_encode(
            [('file', largs_file)],
            cb=_upload_progress)

        request_headers.update({
            'X-HockeyAppToken': 'we use this for hockeyapp upload'
        })

        upload_request = urllib2.Request(request_resource,
                                         request_data, 
                                         request_headers)
        upload_connection = urllib2.urlopen(upload_request)
        upload_response = json.load(upload_connection)
    print "Done"
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文