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

Das Problem kann man auf die Funktion generate_filename zurückführen, und dass year eine Zahl und kein String ist.

Code: Alles auswählen

def generate_filename(symbol, year, week):
    return os.path.join("data", symbol, str(year), '{}.csv.gz'.format(week))
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Die Funktion fetch_single_week funktioniert einwandfrei. Ich habe eine neue Funktion geschrieben

Code: Alles auswählen

# Start date (Year, Month, Day)
start_date = datetime.date(2015, 1, 4)
# End date (Year, Month, Day)
end_date = datetime.date(2016, 2, 9)

Die Codezeilen oben stören mich. Geht es vielleicht innerhalb der Funktion? 

def fetch_time_period(symbol, start_date, end_date):
    for week in range(start_date.isocalendar()[1], end_date.isocalendar()[1]):
        year = str(start_date.isocalendar()[0])
        if not exists_file(symbol, year, week):
            data = pull_file(symbol, year, week)
            print_data_length(data)
            save_file(symbol, year, week, data)
        else:
            print("File for {}/{}/{} already fetched.".format(symbol, year, week))
def main():
Als Ergebnis hätte ich gern:
fetch_time_period("symbol", "2015, 1, 4", "2016, 2, 9")

Aktuell sieht es so aus:
fetch_time_period("symbol", start_date, end_date)

Die Funktion läuft zwar, aber nach dem 5. Durchlauf bricht diese unerwartet ab.
Sirius3
User
Beiträge: 17753
Registriert: Sonntag 21. Oktober 2012, 17:20

@aaron: Dir ist klar, dass das so nicht funktionieren kann. Welchen Wert hat denn year so über die Jahre?
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

der Wert von year über die Jahre. Ich verstehe die Frage nicht ganz. Also wir beginnen 02.01.1999 bis letzte Kalenderwoche des laufenden Jahres. Und es geht jede Woche so weiter. Das meinst du aber mit Sicherheit nicht. year = str(start_date.isocalendar()[0]) scheint falsch zu sein.

year = datetime.datetime.start_date().year ??

Stichwort timedelta?
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Bitte schaut euch die Funktion an. ich möchte ein Anfangsdatum und ein Enddatum eingeben. ich bekomme die Fehlermeldung
for week in range(datetime.date(start_date).isocalendar()[1], datetime.date(end_date).isocalendar()[1]):
TypeError: an integer is required

Code: Alles auswählen

def fetch_time_period(symbol, start_date, end_date):
    for week in range(datetime.date(start_date).isocalendar()[1], datetime.date(end_date).isocalendar()[1]):
            year = str(start_date.isocalendar()[0])
        if not exists_file(symbol, year, week):
            data = pull_file(symbol, year, week)
            print_data_length(data)
            save_file(symbol, year, week, data)
        else:
            print("File for {}/{}/{} already fetched.".format(symbol, year, week))

def main():
    # "symbol", "year, month, day", "year, month, day"
    fetch_time_period("symbol", "2015,1,4", "2016, 3, 4")

if __name__ == '__main__':
    main()
__deets__
User
Beiträge: 14542
Registriert: Mittwoch 14. Oktober 2015, 14:29

Man kann keine ranges mit datetime-Objekten machen. Selbst wenn man koennte, der default von "+1" wuerde keinen Sinn machen - was ist die 1? Eine Sekunde, ein Jahr, ein Aeon? Das muss also schon angegeben werden.

Aber in Python ist so etwas ja schoen einfach selbst geschrieben:

Code: Alles auswählen

import datetime as dt

def daterange(from_, to, step):
    current = from_
    while current < to:
        yield current
        current += step


def main():
    for point in daterange(dt.datetime.now(), dt.datetime.now() + dt.timedelta(days=10), dt.timedelta(days=1)):
        print(point)

if __name__ == '__main__':
    main()
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@aaron: Du übergibst an

Code: Alles auswählen

datetime.date(start_date).isocalendar()[1]
'start_date' als String. Dies verursacht die Fehlermeldung. Statt "2015,1,4" musst Du die drei Integer separat als positionierte Argumente übergeben. Dann kannst Du aber auch direkt den Monat als Integer an range übergeben, denn nichts anderes erhältst Du durch Dein Konstrukt zurück.

Dann wird auch ersichtlich, dass Dein 'for week in range...' nicht das bewirkt, was Du vermutest.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Ich teste soeben das Script und da fallt mir auf, daß das Script mit einer Fehlermeldung abbricht.
Es wird ein Symbol abgefragt, welches nicht auf dem Server vorhanden ist, weil das Symbol nicht vorhanden ist, oder das Datum in der Zukunft liegt. Wenn das Script feststellt, daß einer dieser Fälle eingetroffen ist, dann soll das Script nicht abbrechen, sondern mit der nächsten Aufgabe weitermachen und in ein Logfile schreiben, daß die Files 1.csv.gz - 10.csv.gz heruntergeladen worden sind, aber das File 11.csv.gz noch nicht vorhanden ist.

Code: Alles auswählen

python TickDataCsv27.py 
133135278
data/Alpha/2017/1.csv.gz
161435294
data/Alpha/2017/2.csv.gz
145706620
data/Alpha/2017/3.csv.gz
124924322
data/Alpha/2017/4.csv.gz
135177334
data/Alpha/2017/5.csv.gz
95338134
data/Alpha/2017/6.csv.gz
125369326
data/Alpha/2017/7.csv.gz
122297816
data/Alpha/2017/8.csv.gz
138437782
data/Alpha/2017/9.csv.gz
122760250
data/Alpha/2017/10.csv.gz
Traceback (most recent call last):
  File "TickDataCsv27.py", line 88, in <module>
    main()
  File "TickDataCsv27.py", line 81, in main
    fetch_whole_year("Alpha", 2017)
  File "TickDataCsv27.py", line 60, in fetch_whole_year
    data = pull_file(symbol, year, week)
  File "TickDataCsv27.py", line 19, in pull_file
    response = urllib2.urlopen(url)
  File "/usr/lib64/python2.7/urllib2.py", line 154, in urlopen
    return opener.open(url, data, timeout)
  File "/usr/lib64/python2.7/urllib2.py", line 437, in open
    response = meth(req, response)
  File "/usr/lib64/python2.7/urllib2.py", line 550, in http_response
    'http', request, response, code, msg, hdrs)
  File "/usr/lib64/python2.7/urllib2.py", line 475, in error
    return self._call_chain(*args)
  File "/usr/lib64/python2.7/urllib2.py", line 409, in _call_chain
    result = func(*args)
  File "/usr/lib64/python2.7/urllib2.py", line 558, in http_error_default
    raise HTTPError(req.get_full_url(), code, msg, hdrs, fp)
urllib2.HTTPError: HTTP Error 404: Not Found
Sirius3
User
Beiträge: 17753
Registriert: Sonntag 21. Oktober 2012, 17:20

@aaron: das Stichwort heißt Exception-Handling.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Bitte schaut Euch einmal die Funktion an. Ich verstehe die Fehlermeldung nicht. Ist die Idee richtig?

Code: Alles auswählen

def fetch_time_period(symbol, start_date, end_date):
    for week in rrule.rrule(rrule.WEEKLY, dtstart = datetime.start_date, until = datetime.end_date):
        if not exists_file(symbol, year, week):
            data = pull_file(symbol, year, week)
            print_data_length(data)
            save_file(symbol, year, week, data)
        else:
            print("File for {}/{}/{} already fetched.".format(symbol, year, week))
            
def main():
    fetch_time_period("Alpha", "2015,1,4", "2016, 3, 4")

if __name__ == '__main__':
    main()
Die Fehlermeldung sieht so aus:

Code: Alles auswählen

Traceback (most recent call last):
  File "TickDataCsv27.py", line 92, in <module>
    main()
  File "TickDataCsv27.py", line 89, in main
    fetch_time_period("Alpha", "2015,1,4", "2016, 3, 4")
  File "TickDataCsv27.py", line 60, in fetch_time_period
    for week in rrule.rrule(rrule.WEEKLY, dtstart = datetime.start_date, until = datetime.end_date):
AttributeError: 'module' object has no attribute 'start_date'
Zuletzt geändert von Anonymous am Dienstag 21. März 2017, 22:52, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Sirius3
User
Beiträge: 17753
Registriert: Sonntag 21. Oktober 2012, 17:20

@aaron: warum glaubst Du, dass das Modul datetime ein Attribut start_date hat?
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Gut datetime heraus genommen. Jetzt sieht der Code so aus:

Code: Alles auswählen

# Funktion noch nicht funktionsfähig.
def fetch_time_period(symbol, start_date, end_date):
    for week in rrule.rrule(rrule.WEEKLY, dtstart = start_date, until = end_date):
        if not exists_file(symbol, year, week):
            data = pull_file(symbol, year, week)
            print_data_length(data)
            save_file(symbol, year, week, data)
        else:
            print("File for {}/{}/{} already fetched.".format(symbol, year, week))
Jetzt sieht die Fehlermeldung so aus. Mit toordinal habe ich auch schon herumexperimentiert. Ich habe die Dokumentation auch schon zig mal gelesen. Was ist falsch an der Idee?

Code: Alles auswählen

Traceback (most recent call last):
  File "TickDataCsv27.py", line 92, in <module>
    main()
  File "TickDataCsv27.py", line 89, in main
    fetch_time_period("Alpha", "2015,1, 4", "2016, 3, 4")
  File "TickDataCsv27.py", line 60, in fetch_time_period
    for week in rrule.rrule(rrule.WEEKLY, dtstart = start_date, until = end_date):
  File "/usr/lib/python2.7/site-packages/dateutil/rrule.py", line 240, in __init__
    dtstart = datetime.datetime.fromordinal(dtstart.toordinal())
AttributeError: 'str' object has no attribute 'toordinal'
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@aaron: Nun versuchst Du den String "2015,1,4" als Attribute von datetime anzusprechen und dtstart zuzuweisen, gleiches bei until. Das geht natürlich nicht und schaut – leider – schwer nach Raten aus. Wenn start_date und end_date denn unbedingt dieses Format haben müssen, dann könntest Du diese beiden Strings wie folgt für rrule konvertieren:

Code: Alles auswählen

def fetch_time_period(symbol, start_date, end_date):
    # start_date sei: "2015, 1, 4"
    start_date = datetime.date(*map(int, start_date.split(',')))
    # selbiges mit end_date:
    ...
    for week in rrule.rrule(rrule.WEEKLY, dtstart=start_date, until=end_date):
        ...
oder Dir einen besser passenden Datentyp für die Parameter überlegen; also direkt datetime.date Objekte. Was ich Dir auch sehr empfehlen würde. Denn obiges ist weder schön und noch ist sofort einsichtig, was dort passiert. Und das eher von Nachteil.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@aaron: In einem meiner letzten Posts hatte ich mit dem Hinweis auf

Code: Alles auswählen

datetime.date(start_date).isocalendar()[1]
etwas falsches geschrieben: Wenn Du ein gültiges Date-Objekt als start_date übergibst erhältst Du durch .isocalendar()[1] nicht wieder den Monat, sondern die Woche des betreffenden Jahres zurück. Sorry. Allerdings hat dies keinen Einfluß auf die vorhandenen Fehler.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Ich teste zur Zeit das Script. Ich habe beim Download einiger Symbole folgende Fehlermeldung bekommen: Nach einigem Googlen habe ich gelesen, daß es mit dem Cache auf dem Server zu tun haben könnte. Es gab einen Tipp wie cache = False. Was kann ich tun? Eine komprimierte Datei ist ca. 10 Megabyte groß. Ich wollte 53 Dateien am Stück herunterladen und schon nach der 5 Datei bleibt das Script mit der Fehlermeldung hängen.

Code: Alles auswählen

Traceback (most recent call last):
  File "TickDataCsv27.py", line 81, in <module>
    main()
  File "TickDataCsv27.py", line 76, in main
    fetch_whole_year(symbol, 2015)
  File "TickDataCsv27.py", line 53, in fetch_whole_year
    print_data_length(data)
  File "TickDataCsv27.py", line 28, in print_data_length
    data = f.read()
  File "/usr/lib/python2.7/gzip.py", line 261, in read
    self._read(readsize)
  File "/usr/lib/python2.7/gzip.py", line 320, in _read
    self._add_read_data( uncompress )
  File "/usr/lib/python2.7/gzip.py", line 338, in _add_read_data
    self.extrabuf = self.extrabuf[offset:] + data
MemoryError
Sirius3
User
Beiträge: 17753
Registriert: Sonntag 21. Oktober 2012, 17:20

Das hat nichts mit irgendetwas auf dem Server zu tun. Die unkomprimierten Daten passen einfach nicht in den Arbeitsspeicher. Welche Größe haben denn die Daten unkomprimiert? Du darfst eben nicht alles auf einmal lesen, sondern mußt in Blöcken arbeiten.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Eine Datei unkomprimiert ist zwischen 100 und 130 Megabyte groß. Das sind doch gepackte Dateien im gzip Format, welche zwischen 8,5 und 10 Megabyte groß sind. Also mehr RAM und nur einige wenige Daten herunterladen. Pause machen und dann weder starten. Meinst Du das mit in Blöcken arbeiten?
BlackJack

@aaron: Pause machen hilft nicht wenn man den Speicher voll müllt und nach der Pause damit weiter macht. Es sieht so aus als wenn Du mehr als eine dieser Dateien gleichzeitig entpackt im Speicher hältst, das ist/wird dann halt problematisch. 5 Dateien entpackt sind dann 500 bis 650 MiB, plus vielleicht die ungepackten Daten — wir wissen ja nicht was Du da genau machst.

Du darfst halt immer nur eine Datei zu einer Zeit verarbeiten, also herunterladen, entpacken, speichern. Und dann vielleicht auch nicht die entpackten Daten im Speicher halten. Das macht ja sowieso nicht so viel Sinn. Im `shutil`-Modul gibt es Funktionen die dabei behilflich sein können die Daten direkt vom `GzipFile`-Objekt in ein Dateiobjekt zu kopieren, wobei sie ja auch gleich entpackt werden. Und diese Funktionen lesen auch nicht die komplette Quelldatei in den Speicher, sondern kopieren blockweise.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Vielen Dank für den Hinweis auf das `shutil`-Modul.
@aaron: Pause machen hilft nicht wenn man den Speicher voll müllt und nach der Pause damit weiter macht. Es sieht so aus als wenn Du mehr als eine dieser Dateien gleichzeitig entpackt im Speicher hältst, das ist/wird dann halt problematisch. 5 Dateien entpackt sind dann 500 bis 650 MiB, plus vielleicht die ungepackten Daten — wir wissen ja nicht was Du da genau machst.
Ich habe ein Gitlab Repo angelegt. Hilfe, Tipps, Tricks und konstruktive Kritik sind sehr willkommen.
https://github.com/joergklein/Datawarehouse.git

Ich lerne gerade Handling Exceptions. Entschuldigt bitte meine Fragen. Ich bin Anfänger.
BlackJack

@aaron: Also bei mir läuft das gerade ohne Probleme. Der Traceback verrät ja das es um das Jahr 2015 ging und das Programm ist gerade bei ``data/EURUSD/2015/39.csv.gz``.

Wieviel RAM hast Du denn in dem Rechner?
Antworten