2009-11-25 20 views
20

C'è un modo per scaricare file enormi e in continua crescita su HTTP utilizzando la funzione di download parziale?Download del file con download parziale (HTTP)

Sembra che questo file di codice download da zero ogni volta che si esegue:

import urllib 
urllib.urlretrieve ("http://www.example.com/huge-growing-file", "huge-growing-file") 

mi piacerebbe:

  1. Per recuperare solo i dati appena scritti
  2. Scarica da zero solo se il file sorgente diventa più piccolo (ad esempio è stato ruotato).

risposta

40

E 'possibile fare download parziale utilizzando l'intestazione gamma, i seguenti richiedere una selezionata gamma di byte:

req = urllib2.Request('http://www.python.org/') 
req.headers['Range'] = 'bytes=%s-%s' % (start, end) 
f = urllib2.urlopen(req) 

Ad esempio:

>>> req = urllib2.Request('http://www.python.org/') 
>>> req.headers['Range'] = 'bytes=%s-%s' % (100, 150) 
>>> f = urllib2.urlopen(req) 
>>> f.read() 
'l1-transitional.dtd">\n\n\n<html xmlns="http://www.w3.' 

Usando questa intestazione è possibile riprendi i download parziali. Nel tuo caso tutto ciò che devi fare è tenere traccia delle dimensioni già scaricate e richiedere una nuova gamma.

Ricordare che il server deve accettare questa intestazione perché funzioni.

+2

Inoltre, è necessario controllare l'intestazione Content-Range (potrebbe differire dall'intervallo richiesto) e probabilmente essere pronti per analizzare il corpo multipart/byteranges. –

+2

Controllato nell'aspetto multipart/byteranges. La specifica esclude esplicitamente le risposte multipart/byteranges a una richiesta di intervallo singolo. –

+2

Per recuperare il resto da una posizione attiva (un caso tipico), basta usare '" byte =% d- "' (cioè senza il valore finale). – Alfe

0

Se ho letto correttamente la tua domanda, il file non cambia durante il download, ma viene aggiornato regolarmente. Se questa è la domanda, la risposta è rsync.

Se il file viene aggiornato continuamente anche durante il download, è necessario modificare rsync o un programma bittorrent. Suddividono i file in blocchi separati e scaricano o aggiornano i blocchi in modo indipendente. Quando si arriva alla fine del file dalla prima iterazione, ripetere per ottenere il blocco aggiunto; continuare secondo necessità. Con meno efficienza, si potrebbe solo ripetutamente rsync.

+1

c'è un requisito per HTTP quindi rsync non è una risposta valida –

2

Questo è abbastanza facile da fare utilizzando socket TCP e HTTP non elaborato. L'intestazione della richiesta pertinente è "Range".

Un esempio di richiesta potrebbe essere simile:

mysock = connect(("www.example.com", 80)) 
mysock.write(
    "GET /huge-growing-file HTTP/1.1\r\n"+\ 
    "Host: www.example.com\r\n"+\ 
    "Range: bytes=XXXX-\r\n"+\ 
    "Connection: close\r\n\r\n") 

Dove XXXX rappresenta il numero di byte che hai già recuperati. Quindi puoi leggere le intestazioni di risposta e qualsiasi contenuto dal server. Se il server restituisce un'intestazione come:

Content-Length: 0 

Sai che hai l'intero file.

Se vuoi essere particolarmente bello come un client HTTP si può guardare in "Connection: keep-alive". Forse c'è una libreria Python che fa tutto ciò che ho descritto (forse anche urllib2 lo fa!) Ma non ne conosco uno.

+1

Vedere la risposta di Nadia Alramli. –

+1

Se si esegue il rollover della propria soluzione con i socket TCP, si finisce per eliminare tutte le funzionalità di urllib2, come i reindirizzamenti e la gestione delle impostazioni proxy. –

+0

Assolutamente. Non ricordo che urllib2 abbia supportato l'impostazione di intestazioni di richieste arbitrarie. È (ovviamente) il modo giusto per andare qui. –