Ich habe es geschafft, mein erstes Python-Skript zum Laufen zu bringen, das eine Liste von ZIP-Dateien von einer URL herunterlädt und dann die ZIP-Dateien extrahiert und auf die Festplatte schreibt.
Ich bin jetzt ratlos, den nächsten Schritt zu erreichen.
Mein primäres Ziel ist es, die Zip-Datei herunterzuladen und zu extrahieren und den Inhalt (CSV-Daten) über einen TCP-Stream zu übergeben. Ich würde es vorziehen, keine der Zip- oder extrahierten Dateien auf die Festplatte zu schreiben, wenn ich damit durchkommen könnte.
Hier ist mein aktuelles Skript, das funktioniert, aber leider die Dateien auf die Festplatte schreiben muss.
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" ))
Antworten:
Mein Vorschlag wäre, ein
StringIO
Objekt zu verwenden. Sie emulieren Dateien, befinden sich jedoch im Speicher. Sie könnten also so etwas tun:Oder einfacher (Entschuldigung an Vishal):
Verwenden Sie in Python 3 BytesIO anstelle von StringIO:
quelle
unicode
str
ascii
from io import StringIO
Unten ist ein Codefragment, das ich zum Abrufen einer gezippten CSV-Datei verwendet habe. Schauen Sie sich das an:
Python 2 :
Python 3 :
Hier
file
ist eine Zeichenfolge. Um die tatsächliche Zeichenfolge zu erhalten, die Sie übergeben möchten, können Sie verwendenzipfile.namelist()
. Zum Beispiel,quelle
Ich möchte eine aktualisierte Python 3-Version von Vishals ausgezeichneter Antwort anbieten, die Python 2 verwendet, zusammen mit einigen Erläuterungen zu den Anpassungen / Änderungen, die möglicherweise bereits erwähnt wurden.
Notwendige Änderungen:
StringIO
In Python 3 gibt es kein Modul (es wurde verschobenio.StringIO
). Stattdessen verwende ichio.BytesIO
] 2 , weil wir einen Bytestream - Docs , auch diesen Thread, verarbeiten werden .urllib.urlopen
Funktion von Python 2.6 und früheren Versionen wurde eingestellt.urllib.request.urlopen()
Entspricht der altenurllib2.urlopen
.", Docs und diesem Thread .Hinweis:
b'some text'
. Dies wird erwartet, da es sich nicht um Zeichenfolgen handelt. Denken Sie daran, wir lesen einen Bytestream. Schauen Sie sich die hervorragende Antwort von Dan04 an .Ein paar kleine Änderungen, die ich vorgenommen habe:
with ... as
stattzipfile = ...
nach den Docs ..namelist()
, um alle Dateien in der Zip-Datei zu durchlaufen und deren Inhalt zu drucken.ZipFile
Objekts in diewith
Anweisung verschoben , obwohl ich nicht sicher bin, ob das besser ist."unzipped_and_read_"
den Anfang des Dateinamens und eine".file"
Erweiterung hinzu (ich bevorzuge es, nicht".txt"
für Dateien mit Bytestrings zu verwenden). Der Einzug des Codes muss natürlich angepasst werden, wenn Sie ihn verwenden möchten."wb"
. Ich habe das Gefühl, dass das Schreiben von Binärdateien sowieso eine Dose Würmer öffnet ...Was ich nicht getan habe:
Hier ist ein Weg:
quelle
Schreiben Sie in eine temporäre Datei, die sich im RAM befindet
Es stellt sich heraus, dass das
tempfile
Modul ( http://docs.python.org/library/tempfile.html ) genau das Richtige hat:oder wenn Sie faul sind und ein tmpfs
/tmp
unter Linux gemountet haben , können Sie dort einfach eine Datei erstellen, diese aber selbst löschen und sich mit der Benennung befassenquelle
Der Vollständigkeit halber möchte ich meine Python3-Antwort hinzufügen:
quelle
Hinzufügen zu den anderen Antworten mithilfe von Anfragen :
Verwenden Sie die Hilfe (f) , um weitere Funktionsdetails zu erhalten, z. B. extractall (), das den Inhalt in einer Zip-Datei extrahiert, die später mit open verwendet werden kann .
quelle
with f.open(f.namelist()[0], 'r') as g: df = pd.read_csv(g)
Vishals Beispiel, so großartig es auch sein mag, verwirrt, wenn es um den Dateinamen geht, und ich sehe keinen Vorteil darin, 'zipfile' neu zu definieren.
Hier ist mein Beispiel, das eine Zip-Datei herunterlädt, die einige Dateien enthält. Eine davon ist eine CSV-Datei, die ich anschließend in einen Pandas-DataFrame einlese:
(Hinweis, ich verwende Python 2.7.13)
Dies ist genau die Lösung, die für mich funktioniert hat. Ich habe es nur ein wenig für die Python 3-Version optimiert, indem ich StringIO entfernt und eine E / A-Bibliothek hinzugefügt habe
Python 3 Version
quelle
In Vishals Antwort war nicht ersichtlich, wie der Dateiname lauten sollte, wenn sich keine Datei auf der Festplatte befindet. Ich habe seine Antwort so geändert, dass sie für die meisten Anforderungen ohne Änderung funktioniert.
quelle
Verwenden Sie das
zipfile
Modul. Um eine Datei aus einer URL zu extrahieren, müssen Sie das Ergebnis einesurlopen
Aufrufs in einBytesIO
Objekt einschließen. Dies liegt daran, dass das Ergebnis einer von zurückgegebenenurlopen
Webanforderung die Suche nicht unterstützt:Wenn Sie die Datei bereits lokal heruntergeladen haben, brauchen Sie sie nicht.
BytesIO
Öffnen Sie sie einfach im Binärmodus und übergeben Sie sieZipFile
direkt an:Beachten Sie erneut, dass Sie
open
die Datei im binären ('rb'
) Modus verwenden müssen , nicht als Text, da sonst einezipfile.BadZipFile: File is not a zip file
Fehlermeldung angezeigt wird.Es ist empfehlenswert, all diese Dinge als Kontextmanager für die
with
Anweisung zu verwenden, damit sie ordnungsgemäß geschlossen werden.quelle