2009-11-25 24 views
20

¿Hay alguna manera de descargar archivos grandes y aún en crecimiento a través de HTTP utilizando la función de descarga parcial?Descargar archivo usando descarga parcial (HTTP)

Parece que este archivo de descargas de código desde cero cada vez que se ejecuta:

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

me gustaría:

  1. a buscar solo los datos recién escritos-
  2. Descargar desde cero solo si el archivo de origen se vuelve más pequeño (por ejemplo, se ha rotado).

Respuesta

40

Es posible hacer descarga parcial usando la cabecera gama, lo siguiente será solicitar un rango seleccionado de bytes:

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

Por ejemplo:

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

El uso de esta cabecera se puede reanudar descargas parciales. En su caso, todo lo que tiene que hacer es realizar un seguimiento del tamaño ya descargado y solicitar un nuevo rango.

Tenga en cuenta que el servidor debe aceptar este encabezado para que esto funcione.

+2

También debe verificar el encabezado Content-Range (puede diferir del rango que ha solicitado) y probablemente esté listo para analizar el cuerpo multipart/byteranges. –

+2

Controlado en el aspecto multipart/byteranges. La especificación no permite explícitamente las respuestas multipart/byteranges a una solicitud de rango único. –

+2

Para recuperar el resto desde una posición en (un caso típico), simplemente use '" bytes =% d- "' (es decir, solo sin el valor final). – Alfe

0

Si entiendo su pregunta correctamente, el archivo no cambia durante la descarga, pero se actualiza regularmente. Si esa es la pregunta, rsync es la respuesta.

Si el archivo se actualiza continuamente, incluso durante la descarga, deberá modificar rsync o un programa bittorrent. Dividen los archivos en fragmentos separados y descargan o actualizan los fragmentos de forma independiente. Cuando llegue al final del archivo desde la primera iteración, repita para obtener el fragmento adjunto; continuar según sea necesario. Con menos eficiencia, uno podría simplemente rsync repetidamente.

+1

existe un requisito para HTTP, por lo que rsync no es una respuesta válida –

2

Esto es bastante fácil de hacer usando sockets TCP y HTTP sin formato. El encabezado de solicitud relevante es "Rango".

Un ejemplo de solicitud podría ser:

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 representa el número de bytes que ya ha recuperado. Luego puede leer los encabezados de respuesta y cualquier contenido del servidor. Si el servidor devuelve un encabezado como:

Content-Length: 0 

Sabes que tienes todo el archivo.

Si quiere ser particularmente agradable como cliente HTTP, puede consultar "Conexión: mantener vivo". Tal vez hay una biblioteca de Python que hace todo lo que he descrito (¡quizás incluso lo haga urllib2!) Pero no estoy familiarizado con ninguno.

+1

Consulte la respuesta de Nadia Alramli. –

+1

Si transfiere su propia solución con sockets TCP, termina por deshacerse de todas las funciones en urllib2, como seguir los redireccionamientos y manejar las configuraciones de proxy. –

+0

Absolutamente. No recordaba que urllib2 permitiera configurar encabezados de Solicitud arbitrarios. Es (por supuesto) el camino correcto para ir aquí. –

Cuestiones relacionadas