urllib2 POST进度监控

问题描述:

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

这是可能的,但你需要做的几件事情:

  • 伪造出来的urllib2的子系统为传递文件句柄向下至httplib的通过附加__len__属性,这使得len(data)返回正确的尺寸,用于填充Content-Length标头。
  • 覆盖文件句柄上的read()方法:由于httplib调用read()您的回调将被调用,让您计算百分比并更新您的进度栏。

    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 
    

这可以与任何类似文件的对象的工作,但我已经包裹file显示它如何能与一个真正的大文件,从工作流盘

+0

为什么你把_len_方法?我没有看到httplib在哪里或者你使用它,目的是什么? – MistahX 2011-06-24 02:30:36

+0

它在'urllib2'' AbstractHTTPHandler.do_request _()'和'httplib HttpConnect._send_request()'中使用,其中调用len()来设置Content-length标头。 – samplebias 2011-06-24 03:14:42

+0

优雅的解决方案,谢谢! – knutole 2013-05-15 18:55:12

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

+0

我试图保持它的标准库。这将分发给Windows用户,我不希望他们必须安装额外的东西。 – computergeek6 2011-05-08 03:33:12

+0

那么如果你想出了一些东西,在这里分享:) – zeekay 2011-05-08 03:36:01

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

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"