Seite 1 von 1

HTML-Seite parsen

Verfasst: Samstag 2. August 2014, 01:05
von pixewakb
Hallo zusammen,

ich möchte eine Website einlesen (1), die dortigen Daten auslesen (2) und in der Konsole (später vielleicht mit GUI) ausgeben (3).

(1) Ist klar.

Ich nutze urllib.request.

(2) Ist mir noch nicht klar.

Würdet ihr html.parser verwenden oder im Dokument mit dem re-Modul suchen. Es läuft darauf hinaus die komplette Seite zu lesen, Sidewars, Footer usw. "auszublenden" und die eigentlichen Daten (Content) weiterzuverwenden. Falls html.parser in Frage kommt, wie mache ich das...

Ich habe mir das angelesen: https://docs.python.org/3.4/library/htm ... l#examples.

Eigentlich will ich aber nicht die komplette Seite lesen, sondern nur bestimmte Abschnitte der Website haben und dann zur weiteren Verarbeitung (denke an split, strip usw.) verarbeiten. Also ich will sagen: Gib mir den Inhalt der Div-Box mit der Klasse "Info" zurück... Ich bin auf html.parser gekommen, weil ich beautiful soup bei mir nicht zum Laufen bekam (Python 3.4).

Zwar kann ich auf der Website lesen:
Beautiful Soup 4 works on both Python 2 (2.6+) and Python 3.
In der Praxis schießt es bei mir aber wegen Inkompatibilität ab...

(3) Spontan jemand eine Idee für eine sehr knappe Erklärung Objektorientierte Programmierung in Python? So eine 3 Seiten-Geschichte? Ich habe schon "einige" Ressourcen, aber das ist aktuell sehr viel mehr, als ich wohl zwigend bräuchte. Ich habe mir das vor einem Jahr schon mal intensiv angesehen, müsste es aber ziemlich knapp auffrischen. Wenn nicht, wäre das kein Problem.

Nur am Rande: Bei (2) brauche ich mal eine Einschätzung von jemand anderem, wie er das Problem angehen würde, wahrscheinlich wäre es das dann schon...

Re: HTML-Seite parsen

Verfasst: Samstag 2. August 2014, 01:32
von Hyperion
Du solltest einen HTML-Parser verwenden, wie ``BeautifulSoap`` oder ``lxml.html``. Diese bieten komfortable APIs, u.a. XPath-Support für das Navigieren im HTML-Baum. Über reguläre Ausdrücke solltest Du das Problem nicht angehen; dafür gibt es unzählige Gründe.

Bei (3) ist mir nicht klar, was OOP damit zu tun hat. (Außer, wenn es um GUIs geht natürlich). OOP lernt man nicht auf drei Seiten, sondern durch Übung und Erfahrung. Was / wie genau willst Du denn etwas ausgeben? Ich kann mir vorstellen, dass man bei vielem auch ohne OOP auskommen kann...

Re: HTML-Seite parsen

Verfasst: Samstag 2. August 2014, 01:44
von pixewakb
Ich will Daten einer recht komplexen Website (ohne API) herausholen und zwischenspeichern, so dass ich CSV-Dateien schreiben kann, es einfach pflegen kann usw. usf.

Ich habe es gerade mal testweise mit split, strip usw. gelöst. Das ging auch, ist aber wenig elegant... Ich schaue mir morgen mal die von dir vorgeschlagenen Module an. (Hoffentlich schon auf Python 3 umgestellt :oops: .)

Ich will mal wieder die Grundlagen auffrischen, ohne gefühlt 60 Seiten durchackern zu müssen, die mein Python 3-Buch bietet. Im Kern überlege ich gerade:

* Klassen liegen im Verzeichnis und haben einen Großbuchstaben
* es gibt set- und get-Methoden. Mir stellt sich die Frage: Wenn ich die Daten erst aus einer Website hole, wie packe ich dann die URL-Datenabfrage in die Klasse, das erschließt sich mir gerade nicht.

Ich habe es gerade mittels Funktionen gelöst und zwar so etwas der Art: "sucheName(infobox)". Wahrscheinlich müsste es reichen, wenn ich daraus setName(self, infobox) mache!? [Objektorientierte Orientierung mit einer Klasse Rechteck ist m. E. sehr viel einfacher, als gedanklich dort eine Datenabfrage irgendwie reinzubiegen...]

(Möglicherweise behelfe ich mir erst einmal mit Funktionen...)

Re: HTML-Seite parsen

Verfasst: Samstag 2. August 2014, 01:50
von pixewakb
Ich habe lxml für meine Python-Version 3.4 hier gefunden:

http://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml

Damit komme ich (ganz gut) zurecht. Ich muss mal sehen, ob ich das Konzept verstehe.

Re: HTML-Seite parsen

Verfasst: Samstag 2. August 2014, 09:17
von BlackJack
@pixewakb: (1) Da würde ich das `requests`-Modul vorschlagen. Das hat eine schönere API als `urllib` & Co aus der Standardbibliothek.

(2) `html.parser` aus der Standardbibliothek ist in der Regel ungeeignet um HTML aus der „freien Wildbahn” zu parsen, weil das Modul nur mit korrektem HTML umgehen kann. Und dazu gibt es da draussen einfach viel zu viel kaputtes HTML.

`lxml.html` ist da wesentlich praxistauglicher. Dein Beispiel mit dem <div> mit der Klasse 'Info' kann man da zum Beispiel ganz einfach mit einem CSS-Selektor lösen: ``root.cssselect('div.Info')`` liefert eine Liste mit allen passenden Elementen.

(3) Klassen liegen nicht im Verzeichnis sondern werden in Modulen definiert. Und zwar nicht zwingend nur eine Klasse pro Modul. Python ist nicht Java.

Und `get*()`/`set*()`-Methoden kann es zwar geben, sollte es aber nicht für triviale Getter und Setter, denn auch hier ist Python nicht Java. ;-)

Aus ``suche_name(infobox)`` (bitte unbedingt noch mal Style Guide for Python Code lesen) wird nicht ``set_name(self, infobox)`` sondern wenn dann wohl eher ``get_name(self, infobox)`` oder noch besser ``suche_name(self, infobox)``, denn Methodennamen müssen nicht mit `get*()` oder `set*()` beginnen, oder *noch* besser: Gar keine Methode sondern eine Funktion wenn man das Gefühl hat man würde müsste das irgendwie in die Klasse „reinbiegen”. OOP bedeutet nicht einfach Funktionen in Klassen zu stecken. Klassen sind kein Selbstzweck sondern erfüllen einen Sinn. Und wenn es keinen Sinn macht Funktionen in eine Klasse zu stecken, dann sollte man es bleiben lassen. OOP mit einem `Rechteck` ist wohl auch deswegen einfacher weil dort klar ist was die Daten und die dazugehörigen Operationen sind, die dort in einem Datentyp zusammen gefasst werden. Wofür bei ``suche_name(self, infobox)`` das `self` gebraucht werden soll, wenn es vorher eine Funktion gab die ohne irgendwelche Zusatzinformationen auskam, ist mir zum Beispiel so überhaupt nicht klar. Welchen gemeinsamen Zustand mit welchen anderen Methoden teilt sich `suche_name()` hier?

Re: HTML-Seite parsen

Verfasst: Samstag 2. August 2014, 13:08
von pixewakb
Ich habe das Buch von Michael Weigend zu Python 3 in einer "älteren" Auflage daheim. Objektorientierung ist bei ihm ein Großkapitel mit weiteren Kapiteln und das wird auf einem sehr hohen Niveau verhandelt, was die Informationsdichte und das Beispiel betrifft. Das war aus meiner Sicht nicht sehr einsteigerfreundlich (Meine Meinung).

Mal zu meinem Problem (leider stark vereinfacht):

Sagen wir mal ich habe eine Webseite mit verschiedenen Standorten, wo verschiedene Daten für diesen Standort genannt sind. Der Standort ist durch einen Namen und eine feste URL definiert. Die Seite bietet zu verschiedenen Standorten die Daten, wobei die Seiten jeweils identisch aufgebaut sind und scheinbar auch identische ids und Klassen beim CSS verwenden.

Unglücklicherweise sind da je Standort einige Daten genannt und ich will zumindest nach und nach diese Daten auch in einer Klasse (?) abbilden, um damit arbeiten zu können. Da ich das einmal schreiben und vielleicht erst viel später mal warten und optimieren möchte, habe ich gedacht, dass Klassen eine gute Idee wären.

Was ich machen will, ist z. B. ein Protokoll schreiben und dazu die Daten in geeigneter Form dort abspeichern. Auch möchte ich gerne einzelne Werte verschiedener Standorte einfach miteinander vergleichen können, weshalb ich gedacht habe, dass es später günstiger wäre etwas wie

Code: Alles auswählen

if standort1.wert1 == standort2.wert 2:
...
schreiben zu können. Im Kern muss ich keine Werte selbst setzen, sondern arbeite (erst einmal) immer mit den Werten von der einen Website. Möglicherweise kann es später mal passieren, dass ich als Quelle Daten einer csv-Datei angebe, weshalb dann die URL in der Klasse Mist ist.

Ich frag mal einfach:

Würdest du eine Klasse für den Standort schreiben und z. B. eine zweite Klasse für die Website, die nur die Daten ausliest, oder wie würdest du das anfangen. Nur am Rande: Ich kann mir in Python inzwischen gut helfen, brauche aber dennoch "einfachere" Lösungsansätze, die nicht allzukomplex sind. Aus PHP kenne ich inzwischen Entwurfsmuster (dem Namen nach), wo ich bislang noch keinen Zugang gefunden habe...

Diese Seite http://www.python-kurs.eu/python3_klassen.php scheint ganz brauchbar; wie gesagt das/die Kapitel bei Weigend habe ich schon mal durchgearbeitet, aber das ist viel Stoff und sehr detailliert (didaktisch aus meiner Sicht nicht so gelungen)...

Re: HTML-Seite parsen

Verfasst: Samstag 2. August 2014, 14:03
von BlackJack
@pixewakb: Noch mal: Du musst nicht alles in Klassen stecken. Wenn das extrahieren der Daten mit Funktionen geht, dann verwende dafür halt Funktionen. Klassen erst wenn sie tatsächlich einen Mehrwert bieten.

Einzig um die Daten zu einem Objekt zusammen zu fassen sehe ich in der bisherigen Beschreibung eine Klasse `Standort`. Nach der Beschreibung auch noch ohne Methoden, also würde ein Typ der mit `collections.namedtuple()` erstellt wurde, vielleicht auch erst einmal reichen.

Zur Literatur: Wenn die von `__something` als ``private`` spricht und triviale Getter/Setter propagiert, und `__del__()` als Destruktor bezeichnet und den Eindruck erweckt das wäre eine Methode die man ganz allgemein sinnvoll einsetzen könnte, statt ganz dringend davor zu warnen, dann sollte man sich nach etwas anderem umsehen.

OOP ist zum Teil deswegen so kompliziert zu lernen weil es nur wenige Beispiele gibt die wirklich all die Aspekte abdecken, aber dabei noch einfach und verständlich sind, weil OOP in allen Facetten erst dann sinnvoll wird, wenn man damit komplexere Sachen angeht. Auf der anderen Seite kann man auch bei einfacheren Sachen Klassen benutzen um zusammengehörige Daten und Funktionen die darauf operieren zu Objekten zusammen zu fassen. Aus der bisherigen, sehr allgemeinen Problembeschreibung, ergibt sich da nicht mehr als:

Code: Alles auswählen

class Standort(object):
    def __init__(self, wert_a, wert_b):
        self.wert_a = wert_a
        self.wert_b = wert_b

Re: HTML-Seite parsen

Verfasst: Donnerstag 7. August 2014, 00:17
von pixewakb
Die Methoden programmStart und programmEnde setze ich so ein, d. h. da werden Einstellungen direkt vorgenommen. Also etwa beim Start des Programms, wird die Methode programmStart im Hauptprogramm aufgerufen und programmEnde analog.

Ich habe gesehen, dass es das Logging-Modul gibt, aktuell möchte ich es aber erst einmal selbst schreiben, weil ich noch nicht weiß, ob das Modul für meine Zwecke passt und ich da an einigen Stellen etwas mehr brauche...

Code: Alles auswählen

Help on class Logger in module Logger:

class Logger(builtins.object)
 |  Methods defined here:
 |  
 |  __init__(self)
 |  
 |  getTime(self)
 |  
 |  messageSchreiben(self)
 |  
 |  programmEnde(self)
 |  
 |  programmStart(self)
 |  
 |  set_message(self, nachricht)
 |  
 |  set_messagetyp(self, typ=1)
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  arbeitsverzeichnis = 'logs'
 |  
 |  datum = 'ERROR im Logger!'
 |  
 |  message = 'ERROR im Logger!'
 |  
 |  messagetyp = 'INFO'
 |  
 |  uhrzeit = 'ERROR im Logger!'
Blöde Frage: Abgesehen davon, dass ich deutsche statt englische Begriffe verwende, gibt es bei der Benamung der Methoden etwas, was man so nicht machen würde/sollte? Wahrscheinlich ist der Unterstrich Mist, d. h. besser setMessage. Gibt es anderes, was auf dieser Ebene falsch umgesetzt ist (aktuell bin ich dankbar, dass es läuft und ein praktisch einsetzbares Skript mit OO ist!!!).

Namen vereinheitlichen wäre auch anzuraten, d. h. Verb + Nomen (self)???

Re: HTML-Seite parsen

Verfasst: Donnerstag 7. August 2014, 06:35
von Sirius3
@pixewakb: Du benutzt also so deutsche Namen wie "getTime" und "messageSchreiben". :twisted: Englische Namen sind meist besser, weil die Schlüsselwörter von Python englisch sind, die Bibliotheken englische Methodennamen haben und Du vielleicht irgendwann Dein Programm veröffentlichen willst und dann internationales Publikum abgeschreckt wird. Bevor Du etwas neues erfindest, mach Dich erstmal ausführlich mit dem Logging-Modul vertraut. Es gibt eigentlich nichts, was man nicht an seine Wünsche anpassen kann und bei jeder Anpassung solltest Du Dich fragen, ob derjenige, der das auf diese Art und Weise gelöst hat, nicht mehr Gedanken gemacht hat als Du und sich vielleicht an irgendwelche Standards hält.
Du hast PEP8 in Deiner Signatur und fragst, wie man Methodennamen schreiben soll??? :evil: :evil: :evil:

Re: HTML-Seite parsen

Verfasst: Donnerstag 7. August 2014, 07:31
von BlackJack
@pixewakb: Ich frage mich warum es die Setter gibt und die Attribute `datum`, `message`, `messagetyp`, und `uhrzeit`? Das sieht mir nach einem unnötigen Zwischenschritt aus, der den Logger thread-unsicher macht. Welchen Zustand von dem Logger benötigt `getTime()`? Warum ist `typ` bei `set_messagetyp()` eine Zahl, das Attribut `messagetyp` aber eine Zeichenkette? Warum sind `datum` und `uhrzeit` Zeichenketten, die kein Datum, beziehungsweise keine Uhrzeit darstellen? Warum sind diese beiden Werte getrennt, wo es doch den Typ `datetime.datetime` für so etwas gibt?

Re: HTML-Seite parsen

Verfasst: Sonntag 10. August 2014, 14:19
von pixewakb
Mal eine Zwischenfrage:

Ich frage aktuell mit dem urllib.request-Modul eine Website ab; aktuell ist es im Browser so, dass sie mich im Browser auf eine "Infoseite" weiterleiten, die ich mit "Ich stimme zu" akzeptieren muss, wonach der Content erst gezeigt wird. Ist mit Weiterleitungen gelöst, was ich an den URLs oben im Browser sehen kann. Gibt es eine Möglichkeit so etwas mit Python zu erledigen, d. h. Python zu sagen: "Klicke online" auf den Button und hol dir dann von der Seite die Informationen.

Zum Verständnis:

Bei urllib.request stelle ich es mir vor, dass ich nur statisch eine HTML-Seite aus dem Netz ziehen kann, nicht aber mit dieser Seite vorher noch interagieren könnte. Hat jemand eine Idee?

PS Das ist ein Nebenschauplatz. Ich würde die Infos aus dem Anhang noch gern beziehen, das ist aber nicht erforderlich, um die Aufgabe anzugehen, die ich eigentlich lösen möchte...

Re: HTML-Seite parsen

Verfasst: Sonntag 10. August 2014, 15:30
von BlackJack
@pixewakb: Das kommt alles darauf an wie dieser Dialog gelöst ist und wie/woran die ”Seite” erkennt das Du (noch nicht) zugestimmt hast. Im Grunde muss man aus Sicht des Servers nur das tun was er auch sehen würde wenn man das im Browser macht.

Re: HTML-Seite parsen

Verfasst: Sonntag 10. August 2014, 20:38
von pixewakb
Danke für den Hinweis, ich schaue mir gerade die URL an, das war (auch!!!) ein Hinweis in die richtige Richtung, denke ich. Wenn ich es richtig sehe, dann würde ich denken, dass ich es mit einem PHP-Skript zu tun habe, das eine Umleitung mittels header-Anweisung bewerkstelligt, wenn in der Session noch keine Freigabe für die Seite gespeichert ist.

Klicke ich auf "OK" - ich habe mir noch nicht angesehen, ob es mit PHP, JS oder Ajax geregelt ist, mache ich aber gleich - schickt das Skript mich zurück auf die Ursprungsseite und hat wohl dann in der Sessions-Datei den Eintrag vorgenommen. Schaue ich mir gleich noch mal genau(er) an, ggf. schreibe ich mir für diesen Bereich einen Workaround und notfalls speichere ich die Seiten lokal ab und lasse ein Python-Skript darüberlaufen. Vielleicht auch mal eine gute Gelegenheit sich JS anzusehen, damit geht "Browser-Automatisierung" (oder wie man das nennt) und offenbar könnte ich den Speichervorgang damit vielleicht sogar automatisieren...

(Ich denke noch, wie ich es angehe...) Danke für den Hinweis, war noch nicht auf die Idee gekommen, mir mal die Seite sehr genau anzusehen...

Re: HTML-Seite parsen

Verfasst: Sonntag 10. August 2014, 20:41
von pixewakb
PS Eine Python-Bibliothek, die den Klick eines Buttons erledigen kann und sich mit urllib.request (o. ä.) verträgt, wird es bei Python nicht geben, vermute ich? (Ich hatte bei PHP mal mit der header-Kommunikation zwischen Client und Server zu tun und habe es damals als "recht" kompliziert wahrgenommen, weniger die Befehle, als mehr was da passiert...)

Re: HTML-Seite parsen

Verfasst: Sonntag 10. August 2014, 20:50
von BlackJack
@pixewakb: Man muss ja nicht auf den Button klicken sondern aus Serversicht nur das machen was der Browser in dem Fall macht. Anstelle der Standardbibliothek würde ich das `requests`-Package empfehlen. Das hat eine wesentlich schönere API. Auch wenn man über Abfragen hinweg Cookies verwalten will/muss.

Re: HTML-Seite parsen

Verfasst: Montag 11. August 2014, 05:55
von Sirius3
@pixewakb: Du bringst da einiges an Begriffen durcheinander. Eigentlich braucht Dich nur interessieren, was der Browser macht. Der kann entweder nur einfaches html, entweder Links oder Forms benutzen, dann kann man einfach am HTML-Code ablesen, was gesendet werden muß, oder es wird Javascript verwendet, dann kann man es nicht mehr so einfach ablesen. In beiden Fällen kann man aber die Developertools Deines Browsers anschauen, da werden alle Anfragen an den Server geloggt. Dann mußt Du nur noch feststellen, welche Parameter Du über Python requests senden mußt.