2012-08-23 25 views
7

yavaş indirme işlemini iptal Yavaş (15 saniyede 1MB'den az). Bunu nasıl başarabilirim? Böyleben http üzerinden dosya indirme ve urllib kullanarak ilerlemeyi gösteren ve aşağıdaki kod duyuyorum piton

+1

Rapor sayfanızda bir Özel Durum oluşturabilirsiniz. – Tobold

+1

Evet, durum istisna Google'da hızlı bir bakıştan, indirmeyi durdurmak popüler bir yolu olarak görünmektedir. Ancak belgelerde belirtilmemiş, bu da beklenmedik davranışlara sahip olabileceğinden endişe ediyor. Örneğin, veriler özel bir iş parçacığı tarafından alınabilir ve bir istisna atmak onu bir yetim haline getirecek ve aslında yüklemeyi durdurmayacaktır. – Kevin

cevap

4

Bu çalışması gerekir. Gerçek indirme oranını hesaplar ve çok düşükse iptal eder.

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

Güzel bir, sadece ihtiyacım olan şey, teşekkürler. –

+0

Bunun sadece yavaş bağlantı durumunda çalışacağını unutmayın. Sokete zaman aşımı eklemediğiniz sürece, daha normal bağlantı kesilmez. Aksi halde - Tamam! +1 –

3

şey: Bunu yapabileceğini,

try_one(downloader,15) 

YA:

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 

Eğer zaman aşımına istediğiniz fonksiyon ve zaman çağrı 'try_one' zaman aşımına uğramasına

import socket 
socket.setdefaulttimeout(15) 
+1

Bu, bilinen boyuttaki küçük dosyaları karşıdan yüklüyorsanız iyi bir çözümdür. Boyutu önceden bilmiyorsanız, 'try_one''a kaç saniye geçeceğini bilmeyeceksiniz. Ve eğer bir 100MB dosyası indiriyorsanız, 'try_one (downloader, 1500)' 1500 saniyeye kadar geçmez. Tercihen, indirme işleminin zamanında tamamlanmayacağından emin olur olmaz çıkılır. – Kevin

+0

Evet, kabul etti. Çözüm için teşekkürler, ancak indirme işleminin belirli bir zaman aşımı içinde tamamlanmamasına bağlı olarak minimum iş akışı eşiğine göre iptal etmek istiyorum. –

+0

@HolyMackerel: sadece 10 saniye aralıklarla demek ve hızını kontrol bir Zaman Aşımı olması raporunuzu kanca değiştirin. Sorun, 0 baytın xfered olduğu ve rapor çengelinizin asla çağrılmadığı asılı bir yükleme. –

0

HolyMackerel! Aletleri kullan!

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 

Bu, beklendiği gibi bir durum yazdırır. Benim ethernet kablosu prizden, ben alıyorum: Ben kabloyu prizden Eğer

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


sorry -- try back later 

ardından az 12 saniye içinde tekrar takın, alıyorum: Dosya başarıyla yüklenirse

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! 

.

Sen urllib2 zaman aşımı ve yeniden bağlanır destekler görebilirsiniz. 3 * 4 saniye == 12 saniye için bağlantıyı keser ve bağlantısız kalırsanız, iyi zaman aşımına uğrayacak ve ölümcül bir istisna oluşturacaktır. Bu da ele alınabilir.

+0

sayesinde, güzel bir çözümdür ama durdu indirmeleri ziyade yavaş indirmeleri yakalar. –