HTTP-Download

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
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Hallo zusammen,

momentan versuche ich die Beschaffung von Lieferanten-Dateien, zu automatisieren.
Mit FTP, konnte ich dies schon verwirklichen, was ja auch nicht all zu schwer ist.
Nun habe ich auch HTTP-Downloads, die ich bisher manuell mache.

Beim Googeln, habe ich zwei Möglichkeiten gefunden, die für die Umsetzung in Frage kommen.
Dies sind urllib3 und requests.
Was mir dabei noch nicht klar ist, wo die Unterschiede zwischen urllib3 und requests bestehen und welches vorzuziehen ist?

Mit urllib3, habe ich dies mal erstellt, was bei HTTP ohne Login auch funktioniert:

Code: Alles auswählen

def http_download(import_order):
    """
    Stelle Verbindung zu HTTP-Server her, lade die Datei(en) herunter
    und speichere diese im Download-Ordner.
    """

    url, path, user, passwd, filename, coding, local_path = import_order
    url_file = '{}{}'.format(url, filename)
    if local_path[-1] != os.sep:
        local_path = '{}{}'.format(local_path, os.sep)
    local_file = '{}{}'.format(local_path, filename)
    http = urllib3.PoolManager()
    if (user, passwd) != ('', ''):
        MB().ok('HTTP-Modul für Login noch nicht einsatzbereit!')
        return
    with http.request('GET', url_file, preload_content=False) as resp:
        with open(local_file, 'wb') as out_file:
            shutil.copyfileobj(resp, out_file)
    resp.release_conn()
    if os.path.isfile(os.path.abspath(local_file)):
        return local_file
    return False

import_order = ('https://www.XXXXXX.de/Dowloads/', '', '', '', 'MyFile.zip', 
    '', '/pfad/zu/download_path/')

http_download(import_order)
Nun Habe ich das Gleiche mit requests umgesetzt.
Der Download bei HTTP-Seiten ohne Login, funktioniert hier genauso wie mit obigem Code.
Bei HTTP-Seiten mit Login, habe ich Probleme, dort fehlt der Login fehl.

Code: Alles auswählen

def http_download_request(import_order):
    """
    Stelle Verbindung zu HTTP-Server her, lade die Datei(en) herunter
    und speicher diese im Ordner import_suppliers_lists.
    """

    url, path, user, passwd, filename, coding, local_path = import_order
    url_file = '{}{}'.format(url, filename)
    if local_path[-1] != os.sep:
        local_path = '{}{}'.format(local_path, os.sep)
    if filename == '' or len(filename) == 1:
        filename = heute
    local_file = '{}{}'.format(local_path, filename)

    with open(local_file, 'wb') as handle:
        if (user, passwd) == ('', ''):
            response = requests.get(url_file, stream=True)
        else:
            files = {'file': ('*.csv', path)}
            response = requests.get(
                url, auth=(user, passwd), files=files, stream=True)
            
        if not response.ok:
            # Something went wrong
            print('Fehler: {}'.format(response.ok))
            return
        else:
            print('Juhu: {}'.format(response.ok))
            print(response.text)
            return
        for block in response.iter_content(1024):
            handle.write(block)

    if os.path.isfile(os.path.abspath(local_file)):
        return local_file
    return False

import_order = ('https://www.XXXXXX.de', '~/Dowloads/', 'myuser', 'mapasswd', 'MyFile.zip', 
    '', '/pfad/zu/download_path/')

http_download_request(import_order)
Hier könnte ich Eure Hilfe brauchen!
Welche Informationen sind dafür notwendig?

Grüße Nobuddy
Benutzeravatar
noisefloor
User
Beiträge: 3863
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

was spricht den gegen die urllib, die in Python 3 enthalten ist? Damit kann man doch auch ziemlich viel machen, inkl. Authentifizeriung.

Gruß, noisefloor
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Hallo noisefloor,

keine Ahnung, ob da was dagegen spricht ....
Wo ist der Unterschied zwischen requests und urllib, sind ja beides Python-Module oder?
Bei urllib, gibt es ja urllib, urllib2 und urllib3.
Das sind doch verschiedene Versionen, wobei urllib3 die Aktuellste ist, oder bin ich da falsch?

Grüße Nobuddy
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Nobuddy hat geschrieben:Nun Habe ich das Gleiche mit requests umgesetzt.
Der Download bei HTTP-Seiten ohne Login, funktioniert hier genauso wie mit obigem Code.
Bei HTTP-Seiten mit Login, habe ich Probleme, dort fehlt der Login fehl.
Ein Login erfolgt über einen Post-Request und bei diesem musst Du die Authentifizierungsdaten als HTTPDigestAuth übermitteln:

Code: Alles auswählen

import requests
from requests.auth import HTTPDigestAuth
...
auth = HTTPDigestAuth(user, password)
response = requests.post(url, data=data, headers=headers, auth=auth)
Benutzeravatar
noisefloor
User
Beiträge: 3863
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Bei urllib, gibt es ja urllib, urllib2 und urllib3.
Das sind doch verschiedene Versionen, wobei urllib3 die Aktuellste ist, oder bin ich da falsch?
Halb. In Python 3 gibt es nur urllib. In Python 2 gibt's urllib und urllib 2, was AFAIK historische Gründe hat. Jedenfalls kann urllib in P3 das gleiche wie urllib und urllib 2 in P2.

Warum es requests gibt steht in der Einleitung der Doku. Benutzt habe ich request selber noch nicht, bisher darüber nur gutes gehört :-) requests kann (natürlich) auch Authentifizierung, siehe erstes Beispiel in der Doku.

urllib 3 kannte ich bis zu deinem Post nicht ;-)

Ob die jetzt urllib aus P3 oder request nimmst hängt dann von dir ab :-) Ein HTTP-Download mit oder ohne Auth sollte mit beiden problemlos möglich sein.

Gruß, noisefloor
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

noisefloor hat geschrieben:requests kann (natürlich) auch Authentifizierung, siehe erstes Beispiel in der Doku.
Ah, da hatte ich eine Weile nicht mehr reingeschaut - das Beispiel mit get hatte ich nicht mehr auf dem Schirm. Oftmals erfolgt ein Login aber per Post, und dann, s.o.
BlackJack

@kbr: Ich denke Du verwechselst hier HTTP-Authentifizierung mit Logins die unterhalb des HTTP von Webanwendungen gemacht wird. Denn HTTP-Authentifizierung erfolgt bei jeder Anfrage, also bei jedem GET und jedem POST und nicht nur einmal am Anfang. Das kommt einem ”normalen” Benutzer nur so vor weil er die Zugangsdaten nur einmal beim ersten Zugriff im Browser eingeben muss.

@all: Da `requests` auch `urllib3` benutzt und selbst mitbringt, spricht das IMHO für `requests`, denn dann muss ja auch dessen API nicht viel menschenfreundlicher sein als bei dem/den Modul(en) aus der Standardbibliothek. ;-)

Was ich an `requests` als Python 2 Programmierer auch mag ist das es beide Versionen unterstützt, mir solche Programmteile später bei einer eventuellen Portierung dann weniger Kopfschmerzen bereiten werden.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

BlackJack hat geschrieben:@kbr: Ich denke Du verwechselst hier HTTP-Authentifizierung mit Logins die unterhalb des HTTP von Webanwendungen gemacht wird. Denn HTTP-Authentifizierung erfolgt bei jeder Anfrage, also bei jedem GET und jedem POST und nicht nur einmal am Anfang. Das kommt einem ”normalen” Benutzer nur so vor weil er die Zugangsdaten nur einmal beim ersten Zugriff im Browser eingeben muss.
Nein, ich hatte zuletzt aber eine Anwendung bei der *jeder* Request per POST erfolgte - daher war ich wohl noch auf POST geeicht. Davon unabhängig sehe auch ich 'requests' als gute Empfehlung.
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Hallo zusammen,

also mit BlackJackś Ausführung, liege ich dann wohl mit requests nicht verkehrt. :wink:

Post, ist das was ich brauche, habe ich auch beim Googel erkannt.
Dies steht auch im Quelltext der HTTP-Seite drin:

Code: Alles auswählen

<body id="pageUnknown">
    <form method="post" action="" id="Form1">
Habe mal meinen Code entsprechend geändert und den Code ohne Login weggelassen.

Code: Alles auswählen

def http_download(import_order):
    """
    Stelle Verbindung zu HTTP-Server her, lade die Datei(en) herunter
    und speicher diese im Ordner import_suppliers_lists.
    """

    url, path, user, passwd, filename, coding, local_path = import_order
    url_file = '{}{}{}'.format(url, path, filename)
    if local_path[-1] != os.sep:
        local_path = '{}{}'.format(local_path, os.sep)
    if filename == '' or len(filename) == 1:
        filename = heute
    local_file = '{}{}'.format(local_path, filename)

    with open(local_file, 'wb') as handle:
        data = {"login_act": user, "login_pwd": passwd}
        r = requests.post(url, data=json.dumps(data),
            params=json.dumps(data))
        if r.status_code == 200:
            if "und Kleinschreibung unterschieden." in r.text:
                print("PASSWORT FALSCH")
            else:
                print("PASSWORT RICHTIG")
        else:
            print("Verbindungsfehler")

    if os.path.isfile(os.path.abspath(local_file)):
        return local_file
    return False

import_order = ('https://www.XXXXXX.de/Dowloads/', '', '', '', 'MyFile.zip',
    '', '/pfad/zu/download_path/')

http_download_request(import_order)
In meinem Fall, kommt dann "PASSWORT RICHTIG", das ist doch schon mal ein Schritt in die richtige Richtung.

Nun, wie geht es weiter ....
Hätte ich mich jetzt über meinen Browser (Firefox), auf die entsprechende Seite eingeloggt, würde ich auf den Button "Preisliste" gehen. Danach komme ich in ein neues Fenster, wo ich dann auf den Button "Herunterladen" klicken würde. Was dann wohl weiter geschieht, werde ich wohl nicht weiter ausführen müssen.
Wie müsste nun der nächste Code-Schritt aussehen und welche Information benötige ich dazu?

Grüße Nobuddy
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Zuerst logt man sich ja auf der Hauptseite ein, danach geht es zum Download-Bereich.
Weil ja bei den verschiedenen Internetseiten, z.B. der Download-Bereich unterschidelich untergliedert ist, habe ich mal was ausprobiert.

Code: Alles auswählen

def http_download(import_order):
    """
    Stelle Verbindung zu HTTP-Server her, lade die Datei(en) herunter
    und speicher diese im Ordner import_suppliers_lists.
    """

    url, url_download, user, passwd, filename, coding, local_path = import_order
    url_file = '{}{}{}'.format(url, path, filename)
    if local_path[-1] != os.sep:
        local_path = '{}{}'.format(local_path, os.sep)
    if filename == '' or len(filename) == 1:
        filename = heute
    local_file = '{}{}'.format(local_path, filename)

    with open(local_file, 'wb') as handle:
        data = {"login_act": user, "login_pwd": passwd}
        # Login Startseite und gehe dann auf die Downloadseite
        url_split = url_download.split(url)[1].split(os.sep)
        login2side = url
        for text in url_split:
            print('login2side', login2side)
            r = requests.post(login2side, data=json.dumps(data),
                params=json.dumps(data), stream=True)
            if r.status_code == 200:
                if not "und Kleinschreibung unterschieden." in r.text:
                    print('URL-Position %s' % login2side)
            else:
                print("Verbindungsfehler %s, %s" % (
                    login2side, r.status_code))
                return
            url = '{}{}{}'.format(url, text, os.sep)
            login2side = url
        return
        for block in r.iter_content(1024):
            handle.write(block)

    if os.path.isfile(os.path.abspath(local_file)):
        return local_file
    return False
 
import_order = ('https://www.XXXXXX.de/, 
    'https://www.XXXXXX.de/Dowloads/1234567/ENWPL136M4SO0T0MT78A56O',
    'user', 'mypasswd', '*.csv',
    '', '/pfad/zu/download_path/')

http_download(import_order)
Ich habe das Gleiche auch einzeln getestet, also "requests.post(url, ....)", "requests.post(url_next_path, ....)" usw. .
Obiger Code funktioniert genauso bei mir.
Was meint Ihr dazu, was spricht dafür, was dagegen?

Grüße Nobuddy
Sirius3
User
Beiträge: 17768
Registriert: Sonntag 21. Oktober 2012, 17:20

@Nobuddy: warum hast Du ein Argument import_order das Du entpackst, statt die Argumente gleich anzugeben. Etliche Variablen erscheinen auch aus dem Nichts: path, heute, ... . Variablen sollten immer eine Funktion als Argument betreten und als Rückgabewert verlassen.

Zum Zusammensetzen von Pfaden gibt es os.path.join, Stringformatierung ist da ungeeignet und auch noch deutlich komplizierter. Dieses login2side verstehe ich nicht. Wenn url_download mit url anfangen muß, dann ist doch url überflüssig. Den Anfang eines Strings schneidet man auch nicht mit split ab und os.sep ist nicht der url-Trenner. Wird data jetzt als data oder params an post übertragen? Fehlerbehandlung macht man über Exceptions. Das return in Zeile 33 ist bedingungslos, alles danach wir nie ausgeführt. Der with-open-Block sollte so kurz wie möglich sein.
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

@Sirius3, Du hast natürlich recht, das mit den Variablen ist nicht ok. Werde ich auch ändern.

'https://www.XXXXXX.de/Dowloads/1234567/ ... T0MT78A56O' ist ja in diesem Beispiel der komplette Pfad.
Mir ist jetzt noch nicht klar, wie ich mit 'os.path.join' das erreiche, was ich mit der Strinformatierung umgesetzt habe?
Ein kleines Beispiel dazu, wäre gut. Vielleicht löst sich dann das weitere auf.
Das mit os.sep, wenn ich mir das überlege, kann es nicht der http-Trenner sein. Gibt es dafür eine Funktion, oder einfach nur '/'?

Was data betrifft, hm ... ist mir gerade aufgefallen, steht ja beides drin. :oops:
Habe es mit data sowie params probiert, funktioniert mit beidem, sollte aber data sein.

Das mit der Fehlerbehandlung, hatte erstmals weggelassen, wollte erst mal sehen wie das überhaupt funktioniert.

Werde mal die besagten Stellen ändern, vielleicht hast Du mir dazu evtl. Code-Beispiele?
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Ein paar Änderungen, konnte ich durch Sirius3 umsetzen.

Erste Funktion 'file_check_url_local', soll url und die lokale Zieldatei überprüfen und für die Funktion 'http_download' vorbereiten.
Überprüft wird, ob url und der lokale Ordner eine Datei als Ziel hat.
Hat url keine Datei als Ziel, wird am Ende von url ein '*' hinterlegt.
Hat lokale Ordner keine Datei als Ziel, wird als Dateinamen das heutige Datum mit der Dateiendung aus url verwendet, soweit diese vorhanden ist.

Code: Alles auswählen

def file_check_url_local(url2file, local2file):
    """
    Überprüfung von filename in url2file und local2file.
    """

    url_file_base = False
    url_file = os.path.basename(url2file)
    try:
        url_file.split('.')[-2]
        url_file_base = url_file.split('.')[-1]
    except IndexError:
        url_file = '*'
    if not os.path.isfile(local2file):
        if local2file[-1] != os.sep:
            local2file = '{}{}'.format(local2file, os.sep)
        now = date.today()
        heute = now.strftime('%Y-%m-%d')
        filename = heute
        if '*' in url_file and url_file_base:
            filename = '{}.{}'.format(filename, url_file_base)
        local2file = '{}{}'.format(local_path, filename)
    return url_file, local2file
In der Funktion 'http_download', soll nun der Login zur Hauptseite, sowie das weitere einloggen in die entsprechenden Unterseiten bis zum Ziel erfolgen, wo dann die zur Verfügung stehende Datei, heruntergeladen werden soll.
Login zur Hauptseite, sowie das weitere einloggen in die entsprechenden Unterseiten, funktionieren teilweise.
Da ist bestimmt noch einiges zu machen!

Code: Alles auswählen

def http_download(url, url2file, user, passwd, local2file):
    """
    Stelle Verbindung zu HTTP-Server her, lade die Datei(en) herunter
    und speichere diese im Ordner local2file.
    """

    url_file, local2file = file_check_url_local(url2file, local2file)
    data = {"login_act": user, "login_pwd": passwd}
    # Login Startseite und gehe dann auf die Downloadseite
    url_split = url2file.split(url)[1].split(os.sep)
    for step in url_split:
        r = requests.post(url, data=json.dumps(data))
        try:
            r.raise_for_status()
        except requests.exceptions.HTTPError:
            print("Verbindungsfehler %s\nFehlercode: %s" % (
                url, r.status_code))
            return False
        url = '{}{}{}'.format(url, step, os.sep)
    with open(local2file, 'wb') as handle:
        for block in r.iter_content(1024):
            handle.write(block)

    if os.path.isfile(os.path.abspath(local2file)):
        return local2file
    return False

url, url2file, user, passwd, local2file = (
    'https://www.XXXXXXX.de',
    'https://www.XXXXXXX.de/Pricelist/10069/ENWPL136M4SO0T0MT78A56O/*.csv',
    'user', 'passwd', '/local_path/to/target')

http_download(url, url2file, user, passwd, local2file)
Keine Frage, dass da noch einiges zu tun und verbessern ist.
Hoffe auf Eure Mithilfe!

Grüße Nobuddy
Sirius3
User
Beiträge: 17768
Registriert: Sonntag 21. Oktober 2012, 17:20

@Nobuddy: irgendwie passen Deine Variablennamen nicht zu dem, was getan wird. In file_check_url_local wird nichts gecheckt, local2file ist eine 2 zuviel. url_file_base ist mal ein String, mal ein Boolean. Eine Variable sollte immer nur einen Typ haben. local_path wird nirgends definiert.
Daneben gelten noch fast alle Punkte vom vorherigen Post.

Code: Alles auswählen

def build_local_filename(url, local_path):
    base, ext = os.path.splitext(os.path.basename(url))
    if os.path.isdir(local_path):
        filename = '{0:%Y-%m-%d}{1}'.format(date.today(), ext)
        local_path = os.path.join(local_path, filename)
    return local_path
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

@Sirius3, mit der Vergabe von Namen, habe ich so meine Probleme, mitunter auch durch meine äußerst schlechten Englisch-Kenntnisse.

Danke für Dein Code-Beispiel, kein Vergleich zu meinem. :wink:
Die Exception habe ich eingebaut, sollte doch die Richtige sein, oder?
Eine Lösung für die Stringformatierung, habe ich bisher noch nicht, aber vielleicht bringt mich Dein Code-Beispiel auf die richtige Idee.

Es gibt Internetseiten, die für bestimmte Download-Dateien einen Zufallsgenerator, der einen Namen kreiert. Beispiel W3RFTO7DGR9X.csv
Da gibt es dann zwei Möglichkeiten.
Wenn mir die Dateiendung bekannt ist, macht es Sinn dies in der URL angegeben "https://www.XXXXXXXX.de/Pricelist/10069/*.csv"?
Ist mir klar, bevor ich zu diesem Abschnitt komme, sind noch etliche weitere Probleme zu lösen.

Grüße Nobuddy
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Habe jetzt einiges im Code geändert.

Code: Alles auswählen

import requests
import json
from urllib.parse import urlsplit
from datetime import date


def build_local_filename(url, local_path):
    base, ext = os.path.splitext(os.path.basename(url))
    if os.path.isdir(local_path):
        filename = '{0:%Y-%m-%d}{1}'.format(date.today(), ext)
        local_path = os.path.join(local_path, filename)
    return local_path


def build_requests_post(url, user, passwd):
    data = {"login_act": user, "login_pwd": passwd}
    r = requests.post(url, data=json.dumps(data))
    try:
        r.raise_for_status()
    except requests.exceptions.HTTPError:
        print("Verbindungsfehler %s\nFehlercode: %s" % (url, r.status_code))
        return False
    return r


def http_download(url, user, passwd, local_path):
    """
    Stelle Verbindung zu HTTP-Server her, lade die Datei(en) herunter
    und speicher diese im Ordner import_suppliers_lists.
    """

    local_path = build_local_filename(url, local_path)
    url_split = urlsplit(url)
    base_url = "{0.scheme}://{0.netloc}/".format(url_split)
    path_url = os.path.dirname(url_split.path)
    file_url = os.path.basename(url_split.path)
    path = base_url[:-1]
    if build_requests_post(path, user, passwd):
        for step in path_url.split('/'):
            path = '{}{}/'.format(path, step)
            r = build_requests_post(path, user, passwd)
            try:
                print('headers: %s' % step, '\n', r.headers)
                print('cookies: %s' % step, '\n', r.cookies)
            except AttributeError:
                return False   # Muss noch geändert werden!
    with open(local_path, 'wb') as handle:
        for block in r.iter_content(1024):
            handle.write(block)

    if os.path.isfile(os.path.abspath(local_path)):
        return local_path
    return False

url = 'https://www.XXXXXX.de/Pricelist/10069/ENWPL136M4SO0T0MT78A56O/*.csv'
user = 'user'
passwd = 'passwd'
local_path = '/path/to/target'

http_download(url, user, passwd, local_path)
Bin ich da schon eher auf dem richtigen Weg?

Grüße Nobuddy

PS: Habe nachträglich nochmals Änderungen in der Furnktion 'http_download' vorgenommen.
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Meine letzte Code-Ausgabe, war nicht optimal und zu umständlich. Dies habe ich jetzt versucht zu ändern.
Ich habe 2 Ausgaben von Code erstellt.
Erstens den alten Code neu geschrieben und den zweiten Code, nach diesem Link
http://geophysik.uni-muenchen.de/~krisc ... anced.html gemacht. Den zweiten Code, werde ich der Übersicht halber nicht posten, da er genauso funktioniert wie Code 1 und die gleichen Fehlermeldungen nach URL-Path '~/Pricelist/' bringt.

Code 1:

Code: Alles auswählen

#!/usr/bin/python3
# -*- coding: utf-8

import os
import requests
import json
from urllib.parse import urlsplit
from datetime import date


class HTTP_Download(object):
    """
    Stelle Verbindung zu HTTP-Server her, lade die Datei(en) herunter
    und speichere diese im Ordner local_path.
    """

    def __init__(self, url, user, passwd, local_path):

        self.url, self.user, self.passwd, self.local_path = (url, user,
            passwd, local_path)
        self.local_path = self.build_local_filename()


    def build_local_filename(self):

        base, ext = os.path.splitext(os.path.basename(self.url))
        if os.path.isdir(self.local_path):
            filename = '{0:%Y-%m-%d}{1}'.format(date.today(), ext)
            self.local_path = os.path.join(self.local_path, filename)
        return self.local_path


    def http_download(self):

        url_split = urlsplit(self.url)
        base_url = "{0.scheme}://{0.netloc}/".format(url_split)
        data = {"login_act": user, "login_pwd": passwd}
        path = base_url[:-1]
        for step in url_split.path.split('/'):
            path = '{}{}'.format(path, step)
            if step != url_split.path.split('/')[-1]:
                path = '{}/'.format(path)
            r = requests.post(path, data=json.dumps(data))
            try:
                r.raise_for_status()
            except requests.exceptions.HTTPError:
                print("Verbindungsfehler %s\
                    \nFehlercode: %s" % (path, r.status_code))
        try:
            r.raise_for_status()
            with open(self.local_path, 'wb') as handle:
                for block in r.iter_content(1024):
                    handle.write(block)
            if os.path.isfile(os.path.abspath(self.local_path)):
                return self.local_path
        except requests.exceptions.HTTPError:
            print("Verbindungsfehler %s\
                \nFehlercode: %s" % (path, r.status_code))
        return False


if __name__ == '__main__':
    url = 'https://www.XXXXXX.de/Pricelist/10069/ENWPL136M4SO0T0MT78A56O/10069-XXXXXX-de-preisliste.csv'
    user = 'user'
    passwd = 'passwd'
    local_path = '/path/to/target'
    HTTP_Download(url, user, passwd, local_path).http_download()
Bis URL-Path '~/Pricelist/' erhalte ich 'status_code = 200'.
Ab URL-Path '~/10069/' erhalte ich 'status_code = 404' und kann somit den Download der Datei nicht einleiten.

Gehe ich über meinen Browser und bin im URL-Path 'https://www.XXXXXX.de/Pricelist/', sind dort zwei Buttons.
Der erste ist für den Download als csv-Datei, der zweite als xls-Datei.

Wie muss ich weiter vorgehen, um letztendlich die Datei herunterladen zu können?
Welche Informationen benötigt Ihr, um mir helfen zu können?

Grüße Nobuddy
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Habe jetzt die Lösung gefunden.
Nach dem Einloggen auf die Hauptseite, bin ich mit 'requests.post(base_url, data=json.dumps(data))', in jeden einzelnen Unterpfad gegangen. Darin liegt wahrscheinlich auch der Fehler.
Jetzt habe ich den Code so abgeändert, dass ich mich zuerst in die Hauptseite einlogge und dann anschließend die komplette URL in 'requests.post' verwende. Dies führt dann bei mir zu keinem Fehler und ich kann die Datei herunterladen. :D

Habe nochmals meinen Code optimiert.

Code: Alles auswählen

#!/usr/bin/python3
# -*- coding: utf-8

import os
import requests
import json
from urllib.parse import urlsplit
from datetime import date


class HTTP_Download(object):
    """
    Stelle Verbindung zu HTTP-Server her, lade die Datei(en) herunter
    und speichere diese im Ordner local_path.
    """

    def __init__(self, url, user, passwd, local_path):

        self.url, self.user, self.passwd, self.local_path = (url, user,
            passwd, local_path)
        base, ext = os.path.splitext(os.path.basename(self.url))
        if os.path.isdir(self.local_path):
            filename = '{0}{1}'.format(base, ext)
            self.local_path = os.path.join(self.local_path, filename)


    def http_download(self):

        url_split = urlsplit(self.url)
        base_url = "{0.scheme}://{0.netloc}/".format(url_split)
        data = {"login_act": user, "login_pwd": passwd}
       # Login Haupt-Internetseite
        r = requests.post(base_url, data=json.dumps(data))
        url_path = url_split
        try:
            r.raise_for_status()
           # Gehe zur Download-Datei
            r = requests.post(url, data=json.dumps(data), stream=True)
            url_path = url
            r.raise_for_status()
            with open(self.local_path, 'wb') as handle:
                for block in r.iter_content(1024):
                    handle.write(block)
            if os.path.isfile(os.path.abspath(self.local_path)):
                return self.local_path
        except requests.exceptions.HTTPError:
            print("Verbindungsfehler %s\
                \nFehlercode: %s" % (url_path, r.status_code))
        return False


if __name__ == '__main__':
    url = 'https://www.XXXXXX.de/Pricelist/10069/ENWPL136M4SO0T0MT78A56O/10069-XXXXXX-de-preisliste.csv'
    user = 'user'
    passwd = 'passwd'
    local_path = '/path/to/target'
    HTTP_Download(url, user, passwd, local_path).http_download()
Was mich noch interessiert, wenn ich keine Konkrete Datei zum Download vorliegen habe, wie kann ich mir dann von dem Download-Ordner, die zur Auswahl stehenden Dateien auflisten und ausgeben lassen?

Grüße Nobuddy
Antworten