2011-05-08 4 views
10

urllib2를 사용하여 상당히 큰 파일을 POST를 통해 서버 측 스크립트에 업로드하고 있습니다. 현재 업로드 진행 상태를 보여주는 진행률 표시기를 표시하려고합니다. 업로드 진행 상황을 모니터 할 수있는 urllib2가 제공하는 후크 또는 콜백이 있습니까? 연결의 read() 메서드에 대한 연속적인 호출을 사용하여 다운로드 할 수 있지만 write() 메서드가 표시되지 않는다는 것을 알고 있습니다. 요청에 데이터를 추가하기 만하면됩니다.urllib2 POST 진행 모니터링

답변

23

그것은 가능하지만 당신은 몇 가지 수행해야하는 데 사용 len(data) 반환 정확한 크기를 만드는 __len__ 속성을 부착하여 파일이 HTTPLIB에 핸들을 아래로 전달에 urllib2가 서브 시스템 밖으로

  • 가짜를 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

+0

'urlib2'' AbstractHTTPHandler.do_request _()'와'httplib HttpConnect._send_request()'에서 사용되며'Content-length' 헤더를 설정하기 위해'len ()'이 호출됩니다. – samplebias

+0

우아한 해결책, 고마워! – knutole

0

나는 이것이 가능하다고 생각하지 않지만, pycurl does have upload/download progress callbacks을 사용할 수 있습니다.

+0

을 지원합니다. 이것은 Windows 사용자에게 배포 될 예정이며 추가 물건을 설치하지 않아도됩니다. – computergeek6

+0

글쎄, 뭔가를 생각해 낸다면 여기에서 공유하세요 :) – zeekay

0

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"