Dateien herunterladen und in einem Verzeichnis ablegen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Lewis Carroll - bürgerlich Charles Lutwidge Dodgson, von Beruf Mathematiker - beschreibt den Unterschied um den es hier geht so:
Lewis Carroll hat geschrieben:“You are sad,” the Knight said in an anxious tone: “Let me sing you a song to comfort you.”
“Is it very long?” Alice asked, for she had heard a good deal of poetry that day.
“It's long,” said the Knight, “but it's very, very beautiful. Everybody that hears me sing it - either it brings the tears to their eyes, or else -”
“Or else what?” said Alice, for the Knight had made a sudden pause.
“Or else it doesn't, you know. The name of the song is called ‘Haddocks' Eyes.’”
“Oh, that's the name of the song, is it?" Alice said, trying to feel interested.
“No, you don't understand,” the Knight said, looking a little vexed. “That's what the name is called. The name really is ‘The Aged Aged Man.’”
“Then I ought to have said ‘That's what the song is called’?” Alice corrected herself.
“No, you oughtn't: that's quite another thing! The song is called ‘Ways And Means’: but that's only what it's called, you know!”
“Well, what is the song, then?” said Alice, who was by this time completely bewildered.
“I was coming to that,” the Knight said. “The song really is ‘A-sitting On A Gate’: and the tune's my own invention.”
In specifications, Murphy's Law supersedes Ohm's.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Hier noch einmal eine Zusammenfassung:

Code: Alles auswählen

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))
# Import the file 1.csv.gz from https://example.com/symbol/year/1.csv.gz into the directory data/symbol/year/1.csv.gz
        data_path = os.path.join("data", symbol, year)
        print(data_path)
        if not os.path.exists(data_path):
            os.makedirs(data_path)
            gzipfile = response.read()
            with open(url_data, 'wb') as f:
                f.write(gzipfile)
Die Verzeichnisse werden richtig andgelegt:
data/symbol/year

Folgende Ausgaben werden dabei erzeugt:
https://example.com/symbol/year/1.csv.gz
108336468
data/Alpha/2015
https://example.com/Beta/1999/1.csv.gz
105123380
data/Beta/1999

Aber die Datei wird nicht heruntergeladen und an die richtige Stelle geschoben.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@aaron: Lies doch mal, was Du da geschrieben hast. So eine lange Funktion solltest Du auch dringend in kleinere Teile aufteilen, die Du dann auch separat testen kannst. Es wird wohl nichts passieren, weil Du in einem früheren Lauf schon alle Verzeichnisse erstellt hast. Sollte es doch noch eins geben, das noch nicht existiert hat, dann findet er das Verzeichnis "https:" nicht. Sollte das doch aus irgend einem Grund existieren, wäre wohl die erzeugte Datei leer, weil Du die Daten sie schon vorher komplett gelesen hast.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Ich bekomme es nicht in den Griff. Würde sich bitte jemand herablassen und diese zwei Funktionen für mich schreiben. Ich will auch noch abprüfen ob der Download erfolgreich war oder nicht. Dafür bedarf es wahrscheinlich noch einer weiteren Funktion.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@aaron: wenn das ganze Problem für Dich zu schwierig ist, dann spalte es in Teilprobleme auf, solange, bis Du das Teilproblem lösen kannst. Was sind die drei Dinge, die Du tun willst?
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

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()
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@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?
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

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()
Zuletzt geändert von Anonymous am Donnerstag 16. März 2017, 17:29, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@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.
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.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

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?
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@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)
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

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)
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

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))
    
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

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
In specifications, Murphy's Law supersedes Ohm's.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

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.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@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.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

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?
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@aaron: ich sehe da eine Schleife, die über ein ganzes Jahr geht.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

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()

Antworten