Seite 2 von 9

Re: Dateien herunterladen und in einem Verzeichnis ablegen

Verfasst: Donnerstag 16. März 2017, 16:01
von aaron
Ich habe meine Ideen hier einmal aufgeschrieben

Vorbereiten von csv Dateien zum Download von einem entfernten Server. Es sollen
jeden Montag um 06:00 Uhr (UTC) 21 csvi.gz Dateien mit einer Dateigröße von ca.
8,4 Megabyte heruntergeladen werden. Der erste Download wird aber eine Größe
von 11,8 Gigabyte haben. Danach werden es wöchentlich ca. 177 Megabyte sein.
Nachdem die entsprechenden Dateien in den Verzeichnissen data/symbol/year/1.csv.gzip
bis 52.csv.gzip liegen sollen diese bei Bedarf in eine SQL Datenbank importiert
werden.

Mein Pflichtenheft
1. Downloaden der Dateien
1.1 Wie werden Probleme beim Download durch Verbindungsabbrüche behandelt? Wie oft
soll der Download neu angestoßen werden? Wie geht man mit fehlerhaften
csv.gzip Dateien um?
1.2 Versenden eines Logfiles per Mail.

2. Import in eine SQL Datenbank
2.1 Der Import soll ebenso überwacht werden, wie der Download der csv Dateien.
2.2 Entpacken der Dateien
2.3 Wie werden Probleme beim Import durch Verbindungsabbrüche oder fehlerhafte
Daten behandelt?
2.4 Nach dem Download können die csv.gzip Dateien gelöscht werden. Beim nächsten
Update sollen diese Dateien nicht wieder heruntergeladen werden. Erfolgt kein
Import in eine Datenbank, dann dürfen die Dateien nicht gelöscht werden.
2.3 Versenden eines Logfiles per Mail.

Ich möchte folgende Funktionen schreiben
1. Erstellen einer Funktion, die die Dateien zum Download vorbereitet.
2. Herunterladen und Speichern der Dateien in den entsprechenden Verzeichnissen.
3. Schreiben eines Logfiles und Versenden des Logfiles per Mail.
4. Import der csv.gzip Dateien in eine Datenbank

Ich habe auch ein github repo eingerichtet.

Ich habe heute schon versucht das Script zu strukturieren. Leider bisher ohne Erfolg. Ich freue mich über jede Kritik und Anregung. Bitte legt los.

Code: Alles auswählen

def main():
    # my code here

if __name__ == "__main__":
    main()

Code: Alles auswählen

from StringIO import StringIO
import gzip
import os
import urllib2
import datetime

# base url
url = 'https://example.com/'
# Extension of the file name
url_suffix = '.csv.gz'

symbol = ['Alpha', 'Beta']

# Start date (Year, Month, Day)
start_dt = datetime.date(2015,1,4)
# End date (Year, Month, Day)
end_dt = datetime.date(2015,1,9)

# Find the week of the year for the start
start_wk = start_dt.isocalendar()[1]
# Find the week of the year for the end
end_wk = end_dt.isocalendar()[1]
# Pull out the year of the start
year = str(start_dt.isocalendar()[0])

# The URL is a combination of the symbol, year, and week of the year.
# https://example.com/{instrument}/{year}/{int of week of year}.csv.gz
# Example: https://example.com/symbol/2015/1.csv.gz for the first
# week of the year 2015.

# Beginn funktion 1 Vorbereiten der Verzeichnisse auf dem fremden Server
for symbol in symbol:
    for i in range(start_wk, end_wk):
        url_data = os.path.join(url, symbol, year, str(i)+url_suffix)
        print(url_data)
        request = urllib2.Request(url_data)
        response = urllib2.urlopen(request)
        buf = StringIO(response.read())
        f = gzip.GzipFile(fileobj=buf)
        data = f.read()
        print(len(data))
# Ende Funktion 1. Bis hier läuft das Programm fehlerfrei

# Begin Funktion2 Herunterladen und Einfügen der csv.gzip Dateien in die richtigen Verzeichnisse
data_path = os.path.join("data", symbol, year)
print(data_path)
if not os.path.exists(data_path):
    os.makedirs(data_path)

filename = url_data.split("/")[-1]
print(filename)
with open(filename, 'wb') as g:
    data = g.read()

Re: Dateien herunterladen und in einem Verzeichnis ablegen

Verfasst: Donnerstag 16. März 2017, 16:44
von Sirius3
@aaron: das was Du da an Code zeigst, sind ja keine Funktionen. Kommentare definieren keine Funktionen sondern "def ...". Zudem sind die Kommentare falsch. 'Funktion 1' bereitet keine Verzeichnisse auf dem fremden Server vor, weil das normalerweise per HTTP-Protokoll gar nicht geht.
'Funktion 2' lädt nichts herunter.

Zum Pflichtenheft: zu 1: zum Downloaden gehört ja auch, dass man was mit den downgeloadeten Datein passiert. Das wird in 2.4 beschrieben, was da aber nicht hingehört. Wobei Dateien herunterzuladen und sofort wieder zu löschen sinnlos ist.

Zu den Funktionen: was willst Du mit 1. erreichen? Wie willst Du Dateien zum Download vorbereiten, wenn Du doch gar keinen Server schreiben willst, sondern auf der Client-Seite bist? Lassen wir also weg. Kommen wir zu Funktion 2. Das ist eine schöne Beschreibung einer Funktion: "Herunterladen und speichern der Dateien in den entsprechenden Verzeichnissen" enthält mehrere Informationen: Es gibt mehrere Dateien und Verzeichnisse und es soll was geladen und gespeichert werden. Wenn man etwas mehrmals machen muß, heißt das, man braucht eine Schleife und eine Funktion, die etwas für eine Datei macht. Wie sieht die Schleife aus? Was wird mit einer Datei genau gemacht?

Re: Dateien herunterladen und in einem Verzeichnis ablegen

Verfasst: Donnerstag 16. März 2017, 17:28
von aaron
Es ist wirklich schwer ein Pflichtenheft zu schreiben. Ich habe viele Ideen im Kopf, aber noch Schwierigkeiten diese klar zu definieren. Entschuldige bitte, aber ich beabsichtige Python ernsthaft zu erlernen. An diesem Projekt würde ein versierter Programmierer nicht länger als 2 Stunden arbeiten. Ich brauche hier schon etwas länger.

Fangen wir mit diesem Teil Code an.
Was machen wir mit dem Codeschnipsel? Ist es sinnvoll aus dem Schnipsel eine Funktion zu schreiben? Ich weiß nicht ob hier die main() Funktion richtig ist? So funktioniert sie nicht.

Code: Alles auswählen

dev main()
	for symbol in symbol:
                for i in range(start_wk, end_wk):
                url_data = os.path.join(url, symbol, year, str(i)+url_suffix)
                print(url_data)
                request = urllib2.Request(url_data)
                response = urllib2.urlopen(request)
                buf = StringIO(response.read())
                f = gzip.GzipFile(fileobj=buf)
                data = f.read()
                print(len(data))
        
if __name__ == "__main__":
    main()

Re: Dateien herunterladen und in einem Verzeichnis ablegen

Verfasst: Donnerstag 16. März 2017, 18:22
von Sirius3
@aaron: neben den ganzen Syntaxfehlern macht die Funktion auch zu viel. Eine Funktion ist eine Einheit, die eine spezifische Aufgabe löst. Sie erhält alles was sie an Input braucht über ihre Argumente und hat einen Rückgabewert. Wie ich schon im letzten Beitrag geschrieben habe, wäre es eine Funktion, die *eine* Datei herunterlädt. Eine weitere Funktion wäre es, die Datei auf Fehler zu prüfen. Eine weitere, die Datei an einem bestimmten Ort abzulegen, usw.

Re: Dateien herunterladen und in einem Verzeichnis ablegen

Verfasst: Donnerstag 16. März 2017, 18:28
von BlackJack
@aaron: Das `os.path.join()` ist hier falsch. Eine URL ist kein Dateipfad. Das `Request`-Objekt scheint mir unnötig zu sein, man kann `urlopen()` auch einfach die URL als Zeichenkette übergeben.

Re: Dateien herunterladen und in einem Verzeichnis ablegen

Verfasst: Donnerstag 16. März 2017, 19:14
von aaron
Danke für den Tip. Der Code sieht jetzt so aus:

Code: Alles auswählen

for symbol in symbol:
    for i in range(start_wk, end_wk):
        url_data = url + symbol+'/'+year+'/'+str(i)+url_suffix
        print(url_data)
        response = urllib2.urlopen(url_data)
        buf = StringIO(response.read())
        f = gzip.GzipFile(fileobj=buf)
        data = f.read()
        print(len(data))
Die Ausagbe zeigt:
https://example.com/Alpha/2015/1.csv.gz
108336468
https://example.com/Beta/2015/1.csv.gz
105123380

Gut. Jetzt sollten wir eine Funktion daraus machen. So habe ich es verstanden. Die Variablen sind aber außerhalb der Funktion, also nicht sichtbar für die Funktion. So sieht die Idee aus:

Code: Alles auswählen

dev get_url(url, symbol,year, url_suffix):
    for symbol in symbol:
        for i in range(start_wk, end_wk):
            url_data = url + symbol+'/'+year+'/'+str(i)+url_suffix
            # print(url_data)
            response = urllib2.urlopen(url_data)
            buf = StringIO(response.read())
            f = gzip.GzipFile(fileobj=buf)
            data = f.read()
            # print(len(data))
           return(url_data, data)
Das ist die Fehlermeldung:
dev get_url(url, symbol,year, url_suffix):
SyntaxError: invalid syntax

Wie bekomme ich die Variablen richtig übergeben?

Re: Dateien herunterladen und in einem Verzeichnis ablegen

Verfasst: Donnerstag 16. März 2017, 19:53
von Sirius3
@aaron: es heißt »def« nicht »dev«. start_wk und end_wk kommen aus dem Nichts, sollte doch aber über year berechenbar sein. Du hast immer noch keine Funktion für **eine** Datei. i ist ein schlechter Name für eine Wochennummer. Statt + solltest Du Strings mit .format zusammensetzen:

Code: Alles auswählen

URL_TEMPLATE = "https://example.com/{}/{}/{}.csv.gz"
...
url = URL_TEMPLATE.format(symbol, year, week)

Re: Dateien herunterladen und in einem Verzeichnis ablegen

Verfasst: Donnerstag 16. März 2017, 21:19
von aaron
Für eine Datei funktioniert die Funktion jetzt:

Code: Alles auswählen


    for week in range(start_wk, end_wk):
        url = URL_TEMPLATE.format(symbol, year, week, url_suffix)
        print(url)
        response = urllib2.urlopen(url)
        buf = StringIO(response.read())
        f = gzip.GzipFile(fileobj=buf)
        data = f.read()
        print(len(data))
Schreibe ich jetzt wie unter zu sehen, dann funktioniert der Code nicht.

Code: Alles auswählen

def get_file(URL_TEMPLATE, symbol, start_wk, end_wk, year):
    for week in range(start_wk, end_wk):
        url = URL_TEMPLATE.format(symbol, year, week, url_suffix)
        print(url)
        response = urllib2.urlopen(url)
        buf = StringIO(response.read())
        f = gzip.GzipFile(fileobj=buf)
        data = f.read()
        print(len(data))
        return url, len(data)

Re: Dateien herunterladen und in einem Verzeichnis ablegen

Verfasst: Donnerstag 16. März 2017, 22:00
von aaron
Die Funktion nochmals bearbeitet. Habe noch einige Fehler übersehen.

Code: Alles auswählen

for week in range(start_wk, end_wk):
    url = URL_TEMPLATE.format(symbol, year, week)
    print(url)
    response = urllib2.urlopen(url)
    buf = StringIO(response.read())
    f = gzip.GzipFile(fileobj=buf)
    data = f.read()
    print(len(data))
    

Re: Dateien herunterladen und in einem Verzeichnis ablegen

Verfasst: Donnerstag 16. März 2017, 22:43
von pillmuncher
aaron hat geschrieben:Die Funktion nochmals bearbeitet.[...]
Ich sehe da nirgends eine Funktion. Da solltest du nochmal das Tutorial durcharbeiten, insbesondere das Kapitel über die Definition von Funktionen: https://docs.python.org/2.7/tutorial/co ... -functions

Re: Dateien herunterladen und in einem Verzeichnis ablegen

Verfasst: Freitag 17. März 2017, 08:01
von aaron

Code: Alles auswählen

def get_file(URL_TEMPLATE, symbol, start_wk, end_wk, year):
    for week in range(start_wk, end_wk):
        url = URL_TEMPLATE.format(symbol, year, week)
        print(url)
        response = urllib2.urlopen(url)
        buf = StringIO(response.read())
        f = gzip.GzipFile(fileobj=buf)
        data = f.read()
        print(len(data))
Ich verstehe nicht, wie ich die Funktion ausführen und testen kann. Fehlt in diesem Fall noch das return(url) und return()len(data)? Ist die Funktion so erst einmal richtig? Ohne die Zeile def get_file(URL_TEMPLATE, symbol, start_wk, end_wk, year): ist das Ergebnis erst einmal richtig.

Re: Dateien herunterladen und in einem Verzeichnis ablegen

Verfasst: Freitag 17. März 2017, 08:09
von Sirius3
@aaron: das ist immer noch nicht eine Funktion für ***eine*** Datei. Wenn Du später kompliziertere Sachen lösen willst, solltest Du erst die Aufgabe in sinnvolle Einheiten zerlegen. . return kehrt zur aufrufenden Funktion zurück. Sofort.

Re: Dateien herunterladen und in einem Verzeichnis ablegen

Verfasst: Freitag 17. März 2017, 08:16
von aaron
Bitte erkläre es mir. Für eine Datei. Der Aufruf zeigt doch jetzt für eine Datei
https://example.com/symbol/year/1.csv.gz
108336468

Soll die Datei schon heruntergeladen werden? Und dann das Verzeichnis in das die Datei verschoben werden soll erstellt werden?

Re: Dateien herunterladen und in einem Verzeichnis ablegen

Verfasst: Freitag 17. März 2017, 10:13
von Sirius3
@aaron: ich sehe da eine Schleife, die über ein ganzes Jahr geht.

Re: Dateien herunterladen und in einem Verzeichnis ablegen

Verfasst: Freitag 17. März 2017, 14:48
von aaron
So sieht das Programm aktuell aus. Ich hoffe ich beginne langsam zu verstehen was Sirius3 wir zu sagen versucht. Bitte gebt mir einen Tip zu der Funktion pull_gzip_file. Meine Idee scheint falsch zu sein. Zu der Schleife, die ein ganzes Jahr läuft mußt Du mir noch einiges erklären.

Code: Alles auswählen

def get_url(URL_TEMPLATE, symbol, start_wk, end_wk, year):
    for week in range(start_wk, end_wk):
        url = URL_TEMPLATE.format(symbol, year, week)
        print(url)
        response = urllib2.urlopen(url)
        buf = StringIO(response.read())
        f = gzip.GzipFile(fileobj=buf)
        data = f.read()
        print(len(data))

def check_file(URL_TEMPLATE,symbol, start_wk, end_wk, year):
    for week in range(start_wk, end_wk):
        csv_file = URL_TEMPLATE.format(symbol, year, week)
        if os.path.isfile(csv_file) and os.access(csv_file, os.R_OK):
            print(csv_file, "File exists and is readable")
        else:
            print(csv_file, "File is missing or is not readable")

def mk_dir(symbol, year):
    datapath = os.path.join("data", symbol, year)
    print(datapath)
    if not os.path.exists(datapath):
        os.makedirs(datapath)

def pull_gzip_file(URL_TEMPLATE, symbol, start_wk, end_wk, year):
    for week in range(start_wk, end_wk):
        gzip_file = URL_TEMPLATE.format(symbol, year, week)
        g = urllib2.urlopen(gzip_file)
        data = g.read()
        file_name = gzip_file.split("/")[-1]
        print(file_name)
        with open("file_name", "wb") as file:
            file.write(g.read())

def main():
    get_url(URL_TEMPLATE, symbol, start_wk, end_wk, year)
    check_file(URL_TEMPLATE, symbol, start_wk, end_wk, year)
    mk_dir(symbol, year)
    pull_gzip_file(URL_TEMPLATE, symbol, start_wk, end_wk, year)

if __name__ == '__main__':
    main()


Re: Dateien herunterladen und in einem Verzeichnis ablegen

Verfasst: Freitag 17. März 2017, 15:50
von Sirius3
@aaron: vielleicht hilft ja das, zu verstehen:

Code: Alles auswählen

URL_TEMPLATE = "https://example.com/{}/{}/{}.csv.gz"

def generate_filename(symbol, year, week):
    return os.path.join("data", symbol, year, '{}.csv.gz'.format(week))

def pull_file(symbol, year, week):
    url = URL_TEMPLATE.format(symbol, year, week)
    response = urllib2.urlopen(url)
    return response.read()

def exists_file(symbol, year, week):
    return os.path.isfile(generate_filename(symbol, year, week))

def print_data_length(data):
    f = gzip.GzipFile(fileobj=StringIO(data))
    data = f.read()
    print(len(data))

def save_file(symbol, year, week, data):
    filename = generate_filename(symbol, year, week)
    if not os.path.exists(os.path.dirname(filename)):
        os.mkdirs(os.path.dirname(filename))
    with open(filename, "wb") as output:
        output.write(data)
        
def fetch_whole_year(symbol, year):
    last_week = datetime.date(year, 12, 31).isocalendar()[1]
    for week in range(1, last_week + 1):
        if not exists_file(symbol, year, week):
            data = pull_file(symbol, year, week)
            print_data_length(data)
            save_file(symbol, year, week, data)

Re: Dateien herunterladen und in einem Verzeichnis ablegen

Verfasst: Freitag 17. März 2017, 17:00
von aaron
Danke, langsam wird mir die Idee klarer.
Jetzt ist nur noch die Berechnung der Woche einzufügen, da es ja ein Datum für den Start und für das Ende gibt. Das Ergebnis ist ja eine Liste für die Kalenderwochen 1, 2, 3, 4, usw. Machmal will man auch nur einen gewissen Zeitraum herunterladen. In dem Beispiel die erste Woche 2015.

Code: Alles auswählen

# Start date (Year, Month, Day)
start_dt = datetime.date(2015,1,4)
# End date (Year, Month, Day)
end_dt = datetime.date(2015,1,9)

# Find the week of the year for the start
start_wk = start_dt.isocalendar()[1]
# Find the week of the year for the end
end_wk = end_dt.isocalendar()[1]
# Pull out the year of the start
year = str(start_dt.isocalendar()[0])


def get_url(start_wk, end_wk):
    for week in range(start_wk, end_wk):
        return week

Re: Dateien herunterladen und in einem Verzeichnis ablegen

Verfasst: Freitag 17. März 2017, 17:17
von __deets__
Wieso steht den der meiste Code schon wieder *ausserhalb* einer Funktion?

Re: Dateien herunterladen und in einem Verzeichnis ablegen

Verfasst: Samstag 18. März 2017, 19:18
von pixewakb
Gib mal den Link auf dein github repo (In der Hoffnung, dass man da mehr sehen kann).

Ich habe es mit ähnlichen Aufgaben zu tun. Im konkreten Fall würde ich mittels files = os.listdir(path) die Dateien im Zielverzeichnis prüfen und, falls die neue Datei gzip-file not in files, dann würde ich die Datei dorthin speichern.

Du solltest Dir mal requests anschauen. Ich habe anfangs mit dem urlib...-Zeug gearbeitet und kann nur sagen, dass requests deutlich angenehmer zu schreiben ist.

Re: Dateien herunterladen und in einem Verzeichnis ablegen

Verfasst: Samstag 18. März 2017, 19:49
von aaron
Vielen Dank für die Anfrage. Wie gewünscht hier der Link

https://github.com/joergklein/Datawarehouse.git