descomprimir con comprimir compress carpeta archivos python unzip

python - con - Descargar y descomprimir un archivo.zip sin escribir en el disco



zipfile python (8)

A continuación se muestra un fragmento de código que utilicé para obtener un archivo csv comprimido, eche un vistazo:

Python 2 :

from StringIO import StringIO from zipfile import ZipFile from urllib import urlopen resp = urlopen("http://www.test.com/file.zip") zipfile = ZipFile(StringIO(resp.read())) for line in zipfile.open(file).readlines(): print line

Python 3 :

from io import BytesIO from zipfile import ZipFile from urllib.request import urlopen # or: requests.get(url).content resp = urlopen("http://www.test.com/file.zip") zipfile = ZipFile(BytesIO(resp.read())) for line in zipfile.open(file).readlines(): print(line.decode(''utf-8''))

Aquí el file es una cadena. Para obtener la cadena real que desea pasar, puede usar zipfile.namelist() . Por ejemplo,

resp = urlopen(''http://mlg.ucd.ie/files/datasets/bbc.zip'') zipfile = ZipFile(BytesIO(resp.read())) zipfile.namelist() # [''bbc.classes'', ''bbc.docs'', ''bbc.mtx'', ''bbc.terms'']

Logré hacer funcionar mi primer script python, que descarga una lista de archivos .ZIP de una URL y luego procede a extraer los archivos ZIP y los escribe en el disco.

Ahora estoy perdido para lograr el siguiente paso.

Mi objetivo principal es descargar y extraer el archivo zip y pasar los contenidos (datos CSV) a través de una transmisión TCP. Preferiría no escribir ninguno de los archivos zip o extraídos en el disco si pudiera salirse con la suya.

Aquí está mi script actual que funciona, pero desafortunadamente tiene que escribir los archivos en el disco.

import urllib, urllister import zipfile import urllib2 import os import time import pickle # check for extraction directories existence if not os.path.isdir(''downloaded''): os.makedirs(''downloaded'') if not os.path.isdir(''extracted''): os.makedirs(''extracted'') # open logfile for downloaded data and save to local variable if os.path.isfile(''downloaded.pickle''): downloadedLog = pickle.load(open(''downloaded.pickle'')) else: downloadedLog = {''key'':''value''} # remove entries older than 5 days (to maintain speed) # path of zip files zipFileURL = "http://www.thewebserver.com/that/contains/a/directory/of/zip/files" # retrieve list of URLs from the webservers usock = urllib.urlopen(zipFileURL) parser = urllister.URLLister() parser.feed(usock.read()) usock.close() parser.close() # only parse urls for url in parser.urls: if "PUBLIC_P5MIN" in url: # download the file downloadURL = zipFileURL + url outputFilename = "downloaded/" + url # check if file already exists on disk if url in downloadedLog or os.path.isfile(outputFilename): print "Skipping " + downloadURL continue print "Downloading ",downloadURL response = urllib2.urlopen(downloadURL) zippedData = response.read() # save data to disk print "Saving to ",outputFilename output = open(outputFilename,''wb'') output.write(zippedData) output.close() # extract the data zfobj = zipfile.ZipFile(outputFilename) for name in zfobj.namelist(): uncompressed = zfobj.read(name) # save uncompressed data to disk outputFilename = "extracted/" + name print "Saving extracted file to ",outputFilename output = open(outputFilename,''wb'') output.write(uncompressed) output.close() # send data via tcp stream # file successfully downloaded and extracted store into local log and filesystem log downloadedLog[url] = time.time(); pickle.dump(downloadedLog, open(''downloaded.pickle'', "wb" ))


Agregando a las otras respuestas usando solicitudes :

# download from web import requests url = ''http://mlg.ucd.ie/files/datasets/bbc.zip'' content = requests.get(url) # unzip the content from io import BytesIO from zipfile import ZipFile f = ZipFile(BytesIO(content.content)) print(f.namelist()) # outputs [''bbc.classes'', ''bbc.docs'', ''bbc.mtx'', ''bbc.terms'']

Use la ayuda (f) para obtener más detalles sobre las funciones de, por ejemplo, extractall (), que extrae el contenido en un archivo comprimido con el que luego se puede abrir .


El ejemplo de Vishal, por grande que sea, confunde cuando se trata del nombre del archivo, y no veo el mérito de redefinir ''zipfile''.

Aquí está mi ejemplo que descarga un archivo zip que contiene algunos archivos, uno de los cuales es un archivo csv que posteriormente leo en un DataFrame de pandas:

from StringIO import StringIO from zipfile import ZipFile from urllib import urlopen import pandas url = urlopen("https://www.federalreserve.gov/apps/mdrm/pdf/MDRM.zip") zf = ZipFile(StringIO(url.read())) for item in zf.namelist(): print("File in zip: "+ item) # find the first matching csv file in the zip: match = [s for s in zf.namelist() if ".csv" in s][0] # the first line of the file contains a string - that line shall de ignored, hence skiprows df = pandas.read_csv(zf.open(match), low_memory=False, skiprows=[0])

(Nota, yo uso Python 2.7.13)


Me gustaría agregar mi respuesta de Python3 para que esté completa:

from io import BytesIO from zipfile import ZipFile import requests def get_zip(file_url): url = requests.get(file_url) zipfile = ZipFile(BytesIO(url.content)) zip_names = zipfile.namelist() if len(zip_names) == 1: file_name = zip_names.pop() extracted_file = zipfile.open(file_name) return extracted_file


Me gustaría ofrecer una versión actualizada de Python 3 de la excelente respuesta de Vishal, que estaba usando Python 2, junto con alguna explicación de las adaptaciones / cambios, que ya se han mencionado.

from io import BytesIO from zipfile import ZipFile import urllib.request url = urllib.request.urlopen("http://www.unece.org/fileadmin/DAM/cefact/locode/loc162txt.zip") with ZipFile(BytesIO(url.read())) as my_zip_file: for contained_file in my_zip_file.namelist(): # with open(("unzipped_and_read_" + contained_file + ".file"), "wb") as output: for line in my_zip_file.open(contained_file).readlines(): print(line) # output.write(line)

Cambios necesarios:

  • No hay StringIO en Python 3. En su lugar, utilizo io , y desde allí importo BytesIO , porque BytesIO un bytestream - Docs , también este hilo .
  • urlopen:
    • "La función legacy urllib.urlopen de Python 2.6 y anteriores se ha descontinuado; urllib.request.urlopen () corresponde al antiguo urllib2.urlopen.", Docs .
  • import urllib.request:

Nota:

  • En Python 3, las líneas de salida impresas se verán así: b''some text'' . Esto es esperado, ya que no son cadenas, recuerde, estamos leyendo una copia de prueba. Eche un vistazo a la excelente respuesta de Dan04 .

Algunos cambios menores que hice:

  • Uso with ... as lugar de zipfile = ... según los Documentos .
  • La secuencia de comandos ahora usa namelist() para recorrer todos los archivos en el zip e imprimir sus contenidos.
  • ZipFile la creación del objeto ZipFile a la declaración con, aunque no estoy seguro si eso es mejor.
  • Agregué (y comenté) una opción para escribir el bytestream en el archivo (por archivo en el zip), en respuesta al comentario de NumenorForLife; agrega "unzipped_and_read_" al principio del nombre de archivo y una extensión ".file" (prefiero no usar ".txt" para archivos con cadenas de bytes). La sangría del código, por supuesto, deberá ajustarse si desea usarlo.
    • Necesitamos tener cuidado aquí, porque tenemos una cadena de bytes, usamos el modo binario, por lo que "wb" ; Tengo la sensación de que escribir binarios abre una lata de gusanos de todos modos ...
  • Estoy usando un archivo de ejemplo, el archivo de texto UN / LOCODE :

Lo que no hice:

  • NumenorForLife preguntó por guardar el archivo zip en el disco. No estoy seguro de lo que quiso decir al descargar el archivo comprimido. Esa es una tarea diferente; ver la excelente respuesta de Oleh Prypin .

Aquí hay una manera:

import urllib.request import shutil with urllib.request.urlopen("http://www.unece.org/fileadmin/DAM/cefact/locode/2015-2_UNLOCODE_SecretariatNotes.pdf") as response, open("downloaded_file.pdf", ''w'') as out_file: shutil.copyfileobj(response, out_file)


Mi sugerencia sería usar un objeto StringIO . Emulan archivos, pero residen en la memoria. Entonces podrías hacer algo como esto:

# get_zip_data() gets a zip archive containing ''foo.txt'', reading ''hey, foo'' from StringIO import StringIO zipdata = StringIO() zipdata.write(get_zip_data()) myzipfile = zipfile.ZipFile(zipdata) foofile = myzipfile.open(''foo.txt'') print foofile.read() # output: "hey, foo"

O más simplemente (disculpas a Vishal):

myzipfile = zipfile.ZipFile(StringIO(get_zip_data())) for name in myzipfile.namelist(): [ ... ]

En Python 3 usa BytesIO en lugar de StringIO.


No era obvio en la respuesta de Vishal cuál se suponía que era el nombre del archivo en los casos en que no hay ningún archivo en el disco. He modificado su respuesta para que funcione sin modificaciones para la mayoría de las necesidades.

from StringIO import StringIO from zipfile import ZipFile from urllib import urlopen def unzip_string(zipped_string): unzipped_string = '''' zipfile = ZipFile(StringIO(zipped_string)) for name in zipfile.namelist(): unzipped_string += zipfile.open(name).read() return unzipped_string


escribir en un archivo temporal que reside en la RAM

resulta que el módulo tempfile ( http://docs.python.org/library/tempfile.html ) tiene exactamente lo siguiente:

tempfile.SpooledTemporaryFile ([max_size = 0 [, mode = ''w + b'' [, bufsize = -1 [, sufijo = '''' [, prefijo = ''tmp'' [, dir = None]]]]])

Esta función funciona exactamente como TemporaryFile (), excepto que los datos se almacenan en la memoria hasta que el tamaño del archivo exceda max_size, o hasta que se llame al método fileno (), en cuyo punto los contenidos se escriben en el disco y la operación continúa como con TemporaryFile ().

El archivo resultante tiene un método adicional, rollover (), que hace que el archivo se transfiera a un archivo en disco, independientemente de su tamaño.

El objeto devuelto es un objeto similar a un archivo cuyo atributo _file es un objeto StringIO o un objeto de archivo verdadero, dependiendo de si se ha llamado al rollover (). Este objeto similar a un archivo se puede usar en una declaración con, como un archivo normal.

Nuevo en la versión 2.6.

o si eres perezoso y tienes un tmpfs-mounted /tmp en Linux, puedes hacer un archivo allí, pero debes eliminarlo tú mismo y tratar con los nombres