【问题标题】:urllib2 POST progress monitoringurllib2 POST 进度监控
【发布时间】:2011-08-20 23:14:11
【问题描述】:

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

【问题讨论】:

    标签: python http urllib2 http-post


    【解决方案1】:

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

    • 通过附加__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
    

    【讨论】:

    • 为什么要放 len 方法?没看到httplib或者你在哪里用的,目的是什么?
    • urllib2AbstractHTTPHandler.do_request_()httplib HttpConnect._send_request()中使用,其中len(<file obj>)被调用来设置Content-length头部。
    • 你如何使用 StringIO 来使用这个函数?
    【解决方案2】:

    requests 2.0.0 has streaming uploads。这意味着您可以使用生成器生成小块并打印块之间的进度。

    【讨论】:

      【解决方案3】:

      我认为这是不可能的,但pycurl does have upload/download progress callbacks你可以使用。

      【讨论】:

      • 我正在尝试将其保留在标准库中。这将分发给 Windows 用户,我不希望他们安装额外的东西。
      • 如果你有什么想法,请在这里分享:)
      【解决方案4】:

      poster 支持这个

      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"
      

      【讨论】:

        猜你喜欢
        • 2011-11-01
        • 1970-01-01
        • 2014-06-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多