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.
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: 17750
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: 17750
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()

Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

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

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
__deets__
User
Beiträge: 14540
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wieso steht den der meiste Code schon wieder *ausserhalb* einer Funktion?
Benutzeravatar
pixewakb
User
Beiträge: 1412
Registriert: Sonntag 24. April 2011, 19:43

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

Vielen Dank für die Anfrage. Wie gewünscht hier der Link

https://github.com/joergklein/Datawarehouse.git
Benutzeravatar
pixewakb
User
Beiträge: 1412
Registriert: Sonntag 24. April 2011, 19:43

Wo genau hakt es jetzt im Quellcode? Grob verstehe ich, was Du da machen willst.

Code: Alles auswählen

def get_url(start_wk, end_wk):
    for week in range(start_wk, end_wk):
        pass
    return week
Ich rate oben mal, was Du eigentlich willst. Ich vermute, dass Du die Zahl der Wochen zwischen den zwei Wochen-Daten haben möchtest. Wenn Du in der For-Schleife direkt ein return verbaust, dann wird die Schleife direkt beim ersten Wert für Woche verlassen und 1 zurückgeliefert. Mein Quellcode ändert das. Wenn es nur um die Differenz geht, würde ich die Schleife weglassen und direkt "return end_wk - start_wk" dahinschreiben. Du siehst, dass Du da keine URL erhältst, d. h. der Funktionsname ist falsch.

PS Hättest Du den Link direkt gepostet, wären es nicht 3 Seiten Diskussion geworden.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Das ist meine Lösung

Code: Alles auswählen

def week(start_date, end_date):
    weeks = rrule.rrule(rrule.WEEKLY, dtstart = start_date, until=end_date)
    return weeks.count()
Benutzeravatar
pixewakb
User
Beiträge: 1412
Registriert: Sonntag 24. April 2011, 19:43

Sprachlich scheinst Du besser unterwegs zu sein, als ich. Schön, wenn es klappt.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@aaron: ich seh gerade, dass ich in »fetch_whole_year« eigentlich auch schon viel zu viel mache. Besser wäre es noch ein »fetch_single_week« zu nehmen:

Code: Alles auswählen

def fetch_single_week(symbol, year, week):
    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))
womit man dann einen einzelnen Download ganz einfach testen kann:

Code: Alles auswählen

fetch_single_week("Alpha", 2015, 41)
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Hallo Sirius könntest Du dir bitte noch einmal das Script anschauen. Ich bekommen folgende Fehlermeldung:

Code: Alles auswählen

python TickDataCsv27.py 
Traceback (most recent call last):
  File "TickDataCsv27.py", line 89, in <module>
    main()
  File "TickDataCsv27.py", line 86, in main
    fetch_single_week("EURAUD", 2015, 41)
  File "TickDataCsv27.py", line 71, in fetch_single_week
    if not exists_file(symbol, year, week):
  File "TickDataCsv27.py", line 56, in exists_file
    return os.path.isfile(generate_filename(symbol, year, week))
  File "TickDataCsv27.py", line 48, in generate_filename
    return os.path.join("data", symbol, year, '{}.csv.gz'.format(week))
  File "/usr/lib64/python2.7/posixpath.py", line 75, in join
    if b.startswith('/'):
AttributeError: 'int' object has no attribute 'startswith'
Ich habe noch eine Funktion für das Herunterladen der Daten zwischen einem Startdatum und einem Enddatum eingebaut.
Sirius3
User
Beiträge: 17750
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: 17750
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()
Antworten