Herunterladen und entpacken ein .zip-Datei ohne schreiben auf die Festplatte
Habe ich es geschafft, mein erstes python-Skript zu arbeiten, die downloads eine Liste .ZIP-Dateien von einer URL und geht dann zum extrahieren der ZIP-Dateien und schreibt Sie auf Festplatte.
Ich bin jetzt an einem Verlust zu erreichen, ist der nächste Schritt.
Mein primäres Ziel ist es, download und entpacken Sie die zip-Datei und übergeben Sie den Inhalt (CSV-Daten) über einen TCP-stream. Ich würde es vorziehen, nicht, um tatsächlich schreiben Sie die zip-oder extrahierten Dateien auf die Festplatte, wenn ich könnte mit ihm Weg erhalten.
Hier ist mein Aktuelles script, das funktioniert, aber leider hat das schreiben der Dateien auf die Festplatte.
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" ))
- Warum nicht verwenden Sie temporäre Dateien?
- ZIP-format ist nicht darauf ausgelegt gestreamt werden. Es nutzt Fußzeilen, das heißt, Sie müssen am Ende der Datei, um herauszufinden, wo die Dinge gehören, ist es innen, was bedeutet, Sie brauchen, um die gesamte Datei, bevor Sie irgendetwas tun können, mit einer Teilmenge davon.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Mein Vorschlag wäre, die Nutzung einer
StringIO
Objekt. Sie emulieren Dateien, befinden sich aber in Erinnerung. So konnte man etwas wie das hier tun:Oder mehr einfach (Entschuldigung an Vishal):
In Python 3 verwenden BytesIO statt StringIO.
unicode
Objekte mitstr
Objekte, die nicht decodable durch das system default encoding (in der Regelascii
).from io import StringIO
Unten ist ein code-snippet, das ich verwendet, um zu Holen gezippte csv-Datei, bitte haben Sie einen Blick:
Python 2:
Python 3:
Hier
file
ist ein string. Um die tatsächliche Zeichenfolge, die Sie übergeben möchten, können Siezipfile.namelist()
. Zum Beispiel,namelist
: docs.python.org/2/library/zipfile.html#zipfile.ZipFile.namelist*** TypeError: initial_value must be str or None, not bytes
from urllib.request import urlopen
undfrom io import BytesIO
Würde ich gerne eine aktualisierte Python-3-version von Vishal ausgezeichnete Antwort, die war mit Python 2, zusammen mit einer Erläuterung der Anpassungen /änderungen, die möglicherweise bereits erwähnt.
Notwendigen änderungen:
StringIO
in Python 3. Stattdessen verwende ichio
und von es ich importierenBytesIO
, weil wir Umgang mit einem bytestream -- Docs, auch dieser thread.Hinweis:
b'some text'
. Dies ist erwartet, da Sie nicht Streicher - erinnern Sie sich, wir Lesen einem bytestream. Haben Sie einen Blick auf Dan04 ausgezeichnete Antwort.Ein paar kleine änderungen habe ich vorgenommen:
with ... as
stattzipfile = ...
nach die Docs.namelist()
Durchlaufen Sie alle Dateien im zip-und print-Inhalte.ZipFile
Objekt in der with-Anweisung, obwohl ich bin mir nicht sicher, ob das besser ist."unzipped_and_read_"
an den Anfang des Dateinamens und ein".file"
Erweiterung (ich bevorzuge nicht zu verwenden".txt"
für Dateien mit bytestrings). Die Einrückungen der code natürlich angepasst werden müssen, wenn Sie es verwenden möchten."wb"
; ich habe das Gefühl, dass schreiben binäre öffnet eine Dose Würmer sowieso...Was ich nicht tun:
Hier ist ein Weg:
schreiben in eine temporäre Datei, welche sich im RAM
es stellt sich heraus, das
tempfile
Modul ( http://docs.python.org/library/tempfile.html ) hat nur die Sache ist die:oder wenn Sie faul sind und Sie haben ein tmpfs mounted
/tmp
auf Linux, können Sie einfach eine Datei da, aber Sie haben, um es zu löschen sich selbst und befassen sich mit der BenennungIch möchte noch hinzufügen, dass meine Python ist3 Antwort der Vollständigkeit halber:
Hinzufügen auf die anderen Antworten mit Anfragen:
Verwenden Hilfe(f) zu bekommen, mehr Funktionen, mehr details für z.B. extractall (), die extrahiert den Inhalt in der zip-Datei, die später verwendet werden können, mit mit offenen.
with f.open(f.namelist()[0], 'r') as g: df = pd.read_csv(g)
War es nicht offensichtlich in Herby ' s Antwort, was der name der Datei sollte in Fällen, in denen es keine Datei auf der Festplatte. Ich habe geändert, seine Antwort zu arbeiten, ohne änderungen für die meisten Bedürfnisse.
Vishal Beispiel, aber große, verwirrt, wenn es um den Namen der Datei, und ich sehe nicht das Verdienst der redefing 'zipfile'.
Hier ist mein Beispiel, dass downloads ein zip enthält einige Dateien, von denen eine csv-Datei, die ich anschließend Lesen Sie sich in ein pandas DataFrame:
(Anmerkung, ich benutze Python 2.7.13)
Dies ist genau die Lösung, die für mich gearbeitet. Ich habe gerade optimiert es ein wenig für die Python 3 version durch entfernen von StringIO und das hinzufügen von IO-Bibliothek
Python-3-Version