2012-08-23 17 views
7

में धीमी गति से डाउनलोड मैं http से अधिक फ़ाइलों को डाउनलोड और urllib का उपयोग कर प्रगति को प्रदर्शित करने और निम्नलिखित कोड हूँ - जो ठीक काम करता है:रद्द अजगर

import sys 
from urllib import urlretrieve 

urlretrieve('http://example.com/file.zip', '/tmp/localfile', reporthook=dlProgress) 

def dlProgress(count, blockSize, totalSize): 
    percent = int(count*blockSize*100/totalSize) 
    sys.stdout.write("\r" + "progress" + "...%d%%" % percent) 
    sys.stdout.flush() 

अब मैं भी डाउनलोड अगर यह बहुत जा रहा है पुनः आरंभ करना चाहते हैं धीमा (15 सेकंड में 1 एमबी से कम कहें)। इसे कैसे प्राप्त किया जा सकता है?

+1

आप अपने रिपोर्ट में एक अपवाद उठा सकते हैं। – Tobold

+1

हाँ, Google पर एक त्वरित रूप से, एक अपवाद उठाना डाउनलोड करना बंद करने का एक लोकप्रिय तरीका प्रतीत होता है। हालांकि दस्तावेज में इसका उल्लेख नहीं है, जो मुझे चिंता करता है कि यह अप्रत्याशित व्यवहार हो सकता है। उदाहरण के लिए, हो सकता है कि डेटा समर्पित थ्रेड द्वारा लाया जाता है, और अपवाद फेंकने से यह अनाथ बन जाएगा और वास्तव में डाउनलोड को रोक नहीं पाएगा। – Kevin

उत्तर

4

यह काम करना चाहिए। यह वास्तविक डाउनलोड दर और aborts की गणना करता है यदि यह बहुत कम है।

import sys 
from urllib import urlretrieve 
import time 

url = "http://www.python.org/ftp/python/2.7.3/Python-2.7.3.tgz" # 14.135.620 Byte 
startTime = time.time() 

class TooSlowException(Exception): 
    pass 

def convertBToMb(bytes): 
    """converts Bytes to Megabytes""" 
    bytes = float(bytes) 
    megabytes = bytes/1048576 
    return megabytes 


def dlProgress(count, blockSize, totalSize): 
    global startTime 

    alreadyLoaded = count*blockSize 
    timePassed = time.time() - startTime 
    transferRate = convertBToMb(alreadyLoaded)/timePassed # mbytes per second 
    transferRate *= 60 # mbytes per minute 

    percent = int(alreadyLoaded*100/totalSize) 
    sys.stdout.write("\r" + "progress" + "...%d%%" % percent) 
    sys.stdout.flush() 

    if transferRate < 4 and timePassed > 2: # download will be slow at the beginning, hence wait 2 seconds 
     print "\ndownload too slow! retrying..." 
     time.sleep(1) # let's not hammer the server 
     raise TooSlowException 

def main(): 
    try: 
     urlretrieve(url, '/tmp/localfile', reporthook=dlProgress) 

    except TooSlowException: 
     global startTime 
     startTime = time.time() 
     main() 

if __name__ == "__main__": 
    main() 
+0

अच्छा एक, बस मुझे जो चाहिए, धन्यवाद। –

+0

ध्यान दें कि यह केवल धीमे कनेक्शन के मामले में काम करेगा। अधिक सामान्य गिराए गए कनेक्शन तब तक काम नहीं करेंगे जब तक आप सॉकेट में टाइमआउट नहीं जोड़ते। अन्यथा - ठीक है! +1 –

3

कुछ इस तरह:

class Timeout(Exception): 
    pass 

def try_one(func,t=3): 
    def timeout_handler(signum, frame): 
     raise Timeout() 

    old_handler = signal.signal(signal.SIGALRM, timeout_handler) 
    signal.alarm(t) # triger alarm in 3 seconds 

    try: 
     t1=time.clock() 
     func() 
     t2=time.clock() 

    except Timeout: 
     print('{} timed out after {} seconds'.format(func.__name__,t)) 
     return None 
    finally: 
     signal.signal(signal.SIGALRM, old_handler) 

    signal.alarm(0) 
    return t2-t1 

समारोह आप टाइम आउट करना चाहते हैं और समय के साथ कॉल 'try_one' समयबाह्य करने की:

try_one(downloader,15) 

या, आप यह कर सकते हैं:

import socket 
socket.setdefaulttimeout(15) 
+1

यदि आप ज्ञात आकार की छोटी फ़ाइलों को डाउनलोड कर रहे हैं तो यह एक अच्छा समाधान है। यदि आप समय से पहले आकार नहीं जानते हैं, तो आपको नहीं पता होगा कि 'try_one' को कितने सेकंड पास होंगे। और यदि आप 100 एमबी फ़ाइल डाउनलोड कर रहे हैं, तो 'try_one (डाउनलोडर, 1500)' 1500 सेकेंड तक समाप्त नहीं हो जाएगा। अधिमानतः, जैसे ही यह विश्वास था कि यह डाउनलोड समय पर खत्म नहीं होगा। – Kevin

+0

हां, सहमत हुए। समाधान के लिए धन्यवाद लेकिन मैं न्यूनतम थ्रूपुट थ्रेसहोल्ड के आधार पर रद्द करना चाहता हूं कि यह डाउनलोड एक निश्चित टाइमआउट के भीतर पूरा हो गया है या नहीं। –

+0

@ होली मैकरल: 10 सेकंड अंतराल पर टाइमआउट करने के लिए बस अपनी रिपोर्ट हुक को संशोधित करें और दर की जांच करें। समस्या एक लटका डाउनलोड है जहां 0 बाइट xfered हैं और आपकी रिपोर्ट हुक कभी नहीं कहा जाता है। –

0

HolyMackerel! उपकरण का प्रयोग करें!

import urllib2, sys, socket, time, os 

def url_tester(url = "http://www.python.org/ftp/python/2.7.3/Python-2.7.3.tgz"): 
    file_name = url.split('/')[-1] 
    u = urllib2.urlopen(url,None,1)  # Note the timeout to urllib2... 
    file_size = int(u.info().getheaders("Content-Length")[0]) 
    print ("\nDownloading: {} Bytes: {:,}".format(file_name, file_size)) 

    with open(file_name, 'wb') as f:  
     file_size_dl = 0 
     block_sz = 1024*4 
     time_outs=0 
     while True:  
      try: 
       buffer = u.read(block_sz) 
      except socket.timeout: 
       if time_outs > 3: # file has not had activity in max seconds... 
        print "\n\n\nsorry -- try back later" 
        os.unlink(file_name) 
        raise 
       else:    # start counting time outs... 
        print "\nHmmm... little issue... I'll wait a couple of seconds" 
        time.sleep(3) 
        time_outs+=1 
        continue 

      if not buffer: # end of the download    
       sys.stdout.write('\rDone!'+' '*len(status)+'\n\n') 
       sys.stdout.flush() 
       break 

      file_size_dl += len(buffer) 
      f.write(buffer) 
      status = '{:20,} Bytes [{:.2%}] received'.format(file_size_dl, 
              file_size_dl * 1.0/file_size) 
      sys.stdout.write('\r'+status) 
      sys.stdout.flush() 

    return file_name 

यह अपेक्षित स्थिति को प्रिंट करता है। अगर मैं अपने ईथरनेट केबल अनप्लग, मैं मिलता है:

Downloading: Python-2.7.3.tgz Bytes: 14,135,620 
      827,392 Bytes [5.85%] received 


sorry -- try back later 

अगर मैं केबल अनप्लग, फिर इसे वापस कम से कम 12 सेकंड में प्लग में, मैं मिलता है:

Downloading: Python-2.7.3.tgz Bytes: 14,135,620 
      716,800 Bytes [5.07%] received 
Hmmm... little issue... I'll wait a couple of seconds 

Hmmm... little issue... I'll wait a couple of seconds 
Done! 

फ़ाइल सफलतापूर्वक डाउनलोड किया जाता है।

आप देख सकते हैं कि urllib2 दोनों टाइमआउट और पुन: कनेक्ट करने का समर्थन करता है। यदि आप डिस्कनेक्ट करते हैं और 3 * 4 सेकंड == 12 सेकेंड के लिए डिस्कनेक्ट रहते हैं, तो यह अच्छा होगा और घातक अपवाद बढ़ाएगा। यह भी साथ निपटा जा सकता है।

+0

धन्यवाद, यह एक अच्छा समाधान है लेकिन यह धीमी डाउनलोड के बजाए स्थगित डाउनलोड को पकड़ता है। –