2011-03-14 21 views
7

Sé cómo usar urllib para descargar un archivo. Sin embargo, es mucho más rápido, si el servidor lo permite, descargar varias partes del mismo archivo simultáneamente y luego fusionarlas.Descargar varias partes de un archivo simultáneamente con Python?

¿Cómo se hace eso en Python? Si no puede hacerlo fácilmente con la lib estándar, ¿cualquier lib que le permita hacerlo?

+7

Normalmente, * no * es más rápido descargar varias partes de un archivo en paralelo, porque aún está limitado al cuello de botella de su conexión de red. Solo cuando el servidor permita solo un ancho de banda * limitado por conexión *, obtendrá una mejora. –

+0

Si de alguna manera tiene la impresión de que esto logrará las velocidades de descarga que obtiene con un torrente, le decepcionará descubrir que eso no lo ayudará en un único caso de servidor único. Es * es * más rápido * si * está descargando desde múltiples fuentes * y * que cada uno tiene menos ancho de banda de carga que su ancho de banda de descarga total. Ninguna descarga es más rápida que la descarga directa desde un solo servidor con un ancho de banda de carga (disponible) mayor o igual que el ancho de banda de la descarga. –

+3

@Sven: Eso es falso. En el mundo real, por lo general es mucho más rápido, en la mayoría de las conexiones a la mayoría de los servidores, para descargar con múltiples transmisiones. Es desafortunado, y las causas pueden ser difíciles de rastrear, pero está ahí y mucha gente no tiene más remedio que lidiar con eso. –

Respuesta

6

PycURL puede hacerlo. PycURL es una interfaz de Python para libcurl. Se puede usar para buscar objetos identificados por una URL de un programa de Python, similar al módulo de urllib Python. PycURL es maduro, muy rápido y admite muchas funciones.

+0

OK ¿Cómo funciona? responde la pregunta? – pouya

12

Aunque estoy de acuerdo con la sugerencia de Gregory de utilizar una biblioteca existente, vale la pena señalar que puede hacerlo utilizando el encabezado HTTP Range. Si el servidor acepta solicitudes de rango de bytes, puede iniciar varios subprocesos para descargar varias partes del archivo en paralelo. Este fragmento de código, por ejemplo, sólo se descargará bytes 0..65535 del archivo especificado:

import urllib2 
url = 'http://example.com/test.zip' 
req = urllib2.Request(url, headers={'Range':'bytes=0-65535'}) 
data = urllib2.urlopen(req).read() 

Usted puede determinar el tamaño de los recursos a distancia y ver si soporta el servidor variaron las solicitudes mediante el envío de una petición HEAD:

import urllib2 

class HeadRequest(urllib2.Request): 
    def get_method(self): 
     return "HEAD" 

url = 'http://sstatic.net/stackoverflow/img/sprites.png' 
req = HeadRequest(url) 
response = urllib2.urlopen(req) 
response.close() 
print respose.headers 

las impresiones anteriores:

Cache-Control: max-age=604800 
Content-Length: 16542 
Content-Type: image/png 
Last-Modified: Thu, 10 Mar 2011 06:13:43 GMT 
Accept-Ranges: bytes 
ETag: "c434b24eeadecb1:0" 
Date: Mon, 14 Mar 2011 16:08:02 GMT 
Connection: close 

Desde que podemos ver que el tamaño del archivo es 16542 bytes ('Content-Length') y el servidor soporta niveles de bytes ('Accept-Ranges: bytes').

+1

+1 a solo explicar cómo hacerlo manualmente. –

+0

para que el archivo del tamaño 65535 bytes se pueda dividir en 5 buffers = 13107 ¿Eso significa que el rango de cada buffer saldrá en ? Req = urllib2.Request (url, headers = {'Range': 'bytes = 0-13107 '}) ' ' req2 = urllib2.Petición (url, encabezados = {'Rango': 'bytes = 13108-26214'}) ' ' req3 = urllib2.Request (url, encabezados = {'Rango': 'bytes = 26215-39321'}) ' ' req4 = urllib2.Request (url, headers = {'Range': 'bytes = 39322-52429'}) ' ' req5 = urllib2.Request (url, headers = {'Rango': 'bytes = 52430-65535'}) ' En caso afirmativo, ¿cómo puedo juntarlos usando' data = urllib2.urlopen (req) .read() '? –

+0

@san, una manera simple sería iniciar 5 subprocesos, cada uno de los cuales llama a urlopen(). Read() para un rango y almacena el resultado en un contenedor seguro para subprocesos (una lista o dict hará en este caso). Luego espere en el hilo principal para que terminen esos hilos (join()) y combine las partes. – efotinis

Cuestiones relacionadas