2009-11-25 5 views
20

Gibt es eine Möglichkeit, große und immer noch wachsende Dateien über HTTP herunterzuladen, indem die partielle Download-Funktion verwendet wird?Datei mit partiellem Download (HTTP) herunterladen

Es scheint, dass dieser Code-Downloads von Grund auf Datei jedes Mal, es ausgeführt:

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

Ich mag würde:

  1. holen nur die neu geschriebenen Daten
  2. Herunterladen von Grund auf neu nur wenn die Quelldatei kleiner wird (zB wurde sie gedreht).

Antwort

40

Es ist möglich, Teil-Download mit dem Range-Header zu tun, werden die folgenden ein ausgewähltes Sortiment von Bytes anfordern:

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

Zum Beispiel:

>>> 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.' 

diesen Header verwenden, können Sie partielle Downloads fortsetzen. In Ihrem Fall müssen Sie lediglich die bereits heruntergeladene Größe verfolgen und einen neuen Bereich anfordern.

Beachten Sie, dass der Server diesen Header akzeptieren muss, damit dies funktioniert.

+2

Sie müssen auch Content-Range-Header überprüfen (es kann von dem Bereich, den Sie angefordert haben, abweichen) und wahrscheinlich bereit sein, multipart/byteranges Körper zu analysieren. –

+2

Eingecheckt in den multipart/byteranges Aspekt. Die Spezifikation verbietet explizit Multipart/Byte-Bereiche Antworten auf eine einzige Bereich Anfrage. –

+2

Um den Rest von einer Position auf (einem typischen Fall) zu erhalten, verwenden Sie einfach "" Bytes =% d- "' (also nur ohne den Endwert). – Alfe

0

Wenn ich Ihre Frage richtig verstanden habe, ändert sich die Datei nicht während des Downloads, sondern wird regelmäßig aktualisiert. Wenn das die Frage ist, ist rsync die Antwort.

Wenn die Datei kontinuierlich aktualisiert wird, einschließlich während des Downloads, müssen Sie rsync oder ein BitTorrent-Programm ändern. Sie teilen Dateien in einzelne Stücke und laden oder aktualisieren die Stücke unabhängig voneinander. Wenn Sie von der ersten Iteration an das Ende der Datei gelangen, wiederholen Sie den Vorgang, um den angehängten Chunk zu erhalten. weiter wie nötig. Mit weniger Effizienz könnte man einfach immer wieder rsync.

+1

gibt es eine Anforderung für HTTP, also rsync ist keine gültige Antwort –

2

Dies ist ziemlich einfach mit TCP-Sockets und Raw HTTP zu tun. Der relevante Anfragekopf ist "Range".

Ein Beispiel Anfrage könnte wie folgt aussehen:

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") 

XXXX die Anzahl von Bytes repräsentiert Sie bereits abgerufen. Dann können Sie die Antwortheader und alle Inhalte vom Server lesen. Wenn der Server eine Kopfzeile wie folgt zurückgibt:

Content-Length: 0 

Sie wissen, dass Sie die gesamte Datei haben.

Wenn Sie als HTTP-Client besonders nett sein wollen, können Sie in "Connection: keep-alive" schauen. Vielleicht gibt es eine Python-Bibliothek, die alles tut, was ich beschrieben habe (vielleicht sogar urllib2 tut es!), Aber ich bin nicht vertraut mit einem.

+1

Siehe Nadia Alramli Antwort. –

+1

Wenn Sie Ihre eigene Lösung mit TCP-Sockets rollen, dann werden Sie alle Funktionen in urllib2 los, wie das Folgen von Weiterleitungen und die Handhabung von Proxy-Einstellungen. –

+0

Absolut. Ich konnte mich nicht erinnern, dass urllib2 das Setzen von beliebigen Request-Headern unterstützt hat. Es ist (natürlich) der richtige Weg, hierher zu kommen. –