Descargar el archivo zip devuelto desde la URL

84

Si tengo una URL que, cuando se envía en un navegador web, aparece un cuadro de diálogo para guardar un archivo zip, ¿cómo puedo capturar y descargar este archivo zip en Python?

usuario1229108
fuente
1
Probé la sección Descargar un archivo binario y escribirlo en el disco de esta página que funcionó como chram.
Zeinab Abbasimazar

Respuestas:

32

La mayoría de las personas recomiendan usarlo requestssi está disponible, y la requests documentación lo recomienda para descargar y guardar datos sin procesar desde una URL:

import requests 

def download_url(url, save_path, chunk_size=128):
    r = requests.get(url, stream=True)
    with open(save_path, 'wb') as fd:
        for chunk in r.iter_content(chunk_size=chunk_size):
            fd.write(chunk)

Dado que la respuesta pregunta sobre cómo descargar y guardar el archivo zip, no he entrado en detalles sobre la lectura del archivo zip. Vea una de las muchas respuestas a continuación para conocer las posibilidades.

Si por alguna razón no tiene acceso requests, puede usar urllib.request. Puede que no sea tan robusto como el anterior.

import urllib.request

def download_url(url, save_path):
    with urllib.request.urlopen(url) as dl_file:
        with open(save_path, 'wb') as out_file:
            out_file.write(dl_file.read())

Finalmente, si todavía usa Python 2, puede usar urllib2.urlopen.

from contextlib import closing

def download_url(url, save_path):
    with closing(urllib2.urlopen(url)) as dl_file:
        with open(save_path, 'wb') as out_file:
            out_file.write(dl_file.read())
remitente
fuente
¿Puede agregar el fragmento de muestra también? Sería muy amable de su parte hacerlo
Sarvagya Dubey
203

Por lo que puedo decir, la forma correcta de hacer esto es:

import requests, zipfile, StringIO
r = requests.get(zip_file_url, stream=True)
z = zipfile.ZipFile(StringIO.StringIO(r.content))
z.extractall()

por supuesto, querrá comprobar que el GET fue exitoso r.ok.

Para python 3+, sustituya el módulo StringIO con el módulo io y use BytesIO en lugar de StringIO: aquí hay notas de la versión que mencionan este cambio.

import requests, zipfile, io
r = requests.get(zip_file_url)
z = zipfile.ZipFile(io.BytesIO(r.content))
z.extractall("/path/to/destination_directory")
yoavram
fuente
Gracias por esta respuesta. Lo usé para resolver mi problema al obtener un archivo zip con solicitudes .
gr1zzly be4r
yoavram, en su código, ¿dónde ingreso la url de la página web?
newGIS
25
Si desea guardar el archivo descargado en una ubicación diferente, reemplácelo z.extractall()conz.extractall("/path/to/destination_directory")
user799188
1
Si lo que desea guardar el archivo de la URL que puede hacer: urllib.request.urlretrieve(url, filename).
yoavram
3
Para ayudar a otros a conectar los puntos que me tomó 60 minutos de más, puedes usarlo pd.read_table(z.open('filename'))con lo anterior. Útil si tiene un enlace de URL zip que contiene varios archivos y solo está interesado en cargar uno.
Viernes
12

Con la ayuda de esta publicación de blog , lo tengo funcionando con solo requests. El punto de lo extraño streames que no necesitamos llamar contenta solicitudes grandes, lo que requeriría que se procesen todas a la vez, obstruyendo la memoria. El streamevita esto iterando a través de los datos un fragmento a la vez.

url = 'https://www2.census.gov/geo/tiger/GENZ2017/shp/cb_2017_02_tract_500k.zip'
target_path = 'alaska.zip'

response = requests.get(url, stream=True)
handle = open(target_path, "wb")
for chunk in response.iter_content(chunk_size=512):
    if chunk:  # filter out keep-alive new chunks
        handle.write(chunk)
handle.close()
Jeremiah Inglaterra
fuente
2
Las respuestas no deben depender de enlaces para la mayor parte de su contenido. Los enlaces pueden dejar de funcionar o el contenido del otro lado se puede cambiar para que ya no responda la pregunta. Edite su respuesta para incluir un resumen o una explicación de la información a la que apunta el enlace.
mypetlion
7

Esto es lo que tengo para trabajar en Python 3:

import zipfile, urllib.request, shutil

url = 'http://www....myzipfile.zip'
file_name = 'myzip.zip'

with urllib.request.urlopen(url) as response, open(file_name, 'wb') as out_file:
    shutil.copyfileobj(response, out_file)
    with zipfile.ZipFile(file_name) as zf:
        zf.extractall()
Webucator
fuente
Hola. ¿Cómo puedo evitar este error urllib.error.HTTPError: HTTP Error 302: The HTTP server returned a redirect error that would lead to an infinite loop.?
Victor M Herasme Perez
@VictorHerasmePerez, un código de estado de respuesta HTTP 302 significa que la página se ha movido. Creo que el problema que enfrenta se aborda aquí: stackoverflow.com/questions/32569934/…
Webucator
5

Utilice urllib2.urlopen, o podría intentar usar el Requestsmódulo excelente y evitar los dolores de cabeza de urllib2:

import requests
results = requests.get('url')
#pass results.content onto secondary processing...
aravenel
fuente
1
Pero, ¿cómo se analiza results.content int a zip?
0atman
Utilice el zipfilemódulo: zip = zipfile.ZipFile(results.content). A continuación, sólo analizar a través de los archivos a través de ZipFile.namelist(), ZipFile.open()oZipFile.extractall()
aravenel
5

Vine aquí buscando cómo guardar un archivo .bzip2. Permítanme pegar el código para otros que puedan venir a buscarlo.

url = "http://api.mywebsite.com"
filename = "swateek.tar.gz"

response = requests.get(url, headers=headers, auth=('myusername', 'mypassword'), timeout=50)
if response.status_code == 200:
with open(filename, 'wb') as f:
   f.write(response.content)

Solo quería guardar el archivo como está.

Swateek
fuente
3

Gracias a @yoavram por la solución anterior, mi ruta de URL se vinculó a una carpeta comprimida y encontré un error de BADZipfile (el archivo no es un archivo zip), y fue extraño si intenté varias veces recuperar la URL y descomprimirlo todo de repente, modifico un poco la solución. usando el método is_zipfile según aquí

r = requests.get(url, stream =True)
check = zipfile.is_zipfile(io.BytesIO(r.content))
while not check:
    r = requests.get(url, stream =True)
    check = zipfile.is_zipfile(io.BytesIO(r.content))
else:
    z = zipfile.ZipFile(io.BytesIO(r.content))
    z.extractall()
hindamosh
fuente