lxml.html website parsen und Daten auslesen

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
PythonProgger
User
Beiträge: 5
Registriert: Freitag 26. Juni 2009, 17:57

Hallo, ich hab mich nun im Forum angemeldet da ich mit lxml einfach nicht mehr weiterkomme.

Ich habe mit Python vor zwei Wochen zum Programmieren begonnen. Ich habe es nun geschafft mittels Mechanize mich auf Webseiten einzuloggen, jetzt hänge ich aber jedoch beim parsen und Daten auslesen.

Ich möchte mir von einer Webseite die Temperatur meiner Heimatstadt auslesen. Ich habs auf unzählige Arten probiert, bin jedoch immer mit diversen Fehlermeldungen gescheitert.
Eine Woche habe ich gebraucht bis ich mich mittels Mechanize auf einer Webseite einloggen konnte. Jetzt kämpfe ich mit dem parsen und Daten auslesen ebenfalls schon eine Woche. Haha, schön langsam mag ich nicht mehr ;P. Deshalb bitte ich nun um eure Hilfe.
Vielleicht könnt ihr mir mein Beispiel erweitern und die Temperatur der Stadt Linz mittels lxml von der Webseite auslesen.

Herzlichen Dank im voraus.

Code: Alles auswählen

import mechanize
import ClientForm
import BeautifulSoup
import re
from BeautifulSoup import BeautifulSoup 
import lxml
from lxml import etree
import StringIO

SHOW_COOKIES = True

br = mechanize.Browser()

if SHOW_COOKIES:
    cj = mechanize.CookieJar()
    br.set_cookiejar(cj)
    
response = br.open("http://www.bergfex.at/oberoesterreich/wetter/stationen/linz/")

if SHOW_COOKIES:
    for cookie in cj:
        print cookie

assert br.viewing_html()
print '\n-----> Website title <-----'
print br.title()
print '\n-----> Website url <-----'
print br.geturl()  
print '\n-----> Website header <-----'
print response.info()  # headers
print '\n-----> Website body <-----'
#print response.read()  # body

websitehtmlinhalt=br.response()

#Wetterstation Linz - Temperatur auslesen
Benutzeravatar
Dill
User
Beiträge: 470
Registriert: Mittwoch 10. Januar 2007, 14:52
Wohnort: Köln

auch wenn es nicht funktionierst, poste doch mal den code den du zum parsen benutzt.
http://www.kinderpornos.info
PythonProgger
User
Beiträge: 5
Registriert: Freitag 26. Juni 2009, 17:57

Code: Alles auswählen

websitehtmlinhalt=br.response()

#Wetterstation Linz - Temperatur auslesen

#doc = etree.HTMLParser( websitehtmlinhalt )
doc = etree.parse ( websitehtmlinhalt )
print doc
Ich zweifle schon ob ich überhaupt verstanden habe was ein Parser überhaupt ist und was der auch so macht!?

Meinem jetzigen Verständnis nach wird der <body> der Website ausgelesen und in "websitehtmlinhalt" hinterlegt.
Mit etree.parse wird der Inhalt sozusagen zur Verarbeitung umgewandelt und im "doc" hinterlegt.
Das "doc" möchte ich mir im Python Interactive Window mit print ausgeben lassen. Jedoch kommt die Fehlermeldung :

-----> Website body <-----
Traceback (most recent call last):
File "C:\Python26\Lib\site-packages\pythonwin\pywin\framework\scriptutils.py", line 312, in RunScript
exec codeObject in __main__.__dict__
File "C:\Python26\feichti_scripts\test_Wetter_auslesen_Linz_Login_PythonForum_01.py", line 41, in <module>
doc = etree.HTMLParser( websitehtmlinhalt )
File "parser.pxi", line 1353, in lxml.etree.HTMLParser.__init__ (src/lxml/lxml.etree.c:74475)
TypeError: __init__() takes exactly 0 positional arguments (1 given)


Wie gesagt, ich scheitere schon am Auslesen des Inhaltes, da brauch ich mich derzeit noch gar nicht mit dem Zugriff auf die ausgelesenen Daten beschäftigen.
BlackJack

@PythonProgger: Hier passen Quelltext und Fehlermeldung aber nicht zusammen, denn Python führt keine Kommentare aus. Der Aufruf, der zu dieser Fehlermeldung führt, ist auskommentiert.

Und die Fehlermeldung ist doch ziemlich deutlich: `etree.HTMLParser()` erwartet keine Argumente, Du hast aber eines angegeben.
Benutzeravatar
snafu
User
Beiträge: 6744
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

PythonProgger hat geschrieben:Ich zweifle schon ob ich überhaupt verstanden habe was ein Parser überhaupt ist und was der auch so macht!?
Nach bestimmt 2 Stunden Recherche habe ich das gefunden. :)

Zusammengefasst in etwa: Ein HTML-Parser bildet HTML-Code, der ursprünglich für Python nichts anderes als jeder andere Text auch ist, in einer betimmten Datenstruktur ab, die du dann ansprechen kannst. Mit entsprechender Syntax könntest du z.B. alle Links (also das jeweilige href-Attribut von den a-Elementen) raussuchen, ohne groß mit irgendwelchen Reckechsen rumhantieren zu müssen.
Benutzeravatar
Dill
User
Beiträge: 470
Registriert: Mittwoch 10. Januar 2007, 14:52
Wohnort: Köln

du bist zwei wochen dabei und stellst dir direkt solche aufgaben?
das kann leicht in frust enden. mit etwas mehr übung hättest du zb die fehlermeldung richtig interpretiert.

was hast du denn zur einführung in python gelsen/bearbeitet?

du solltest dein problem mal in mehrere teile aufspalten:

1. zugriff auf die gewünschte html-seite.
das hast du mit mechanize gelöst. es geht zwar einfacher, aber warum nicht.

2. HTML parsen
2a. dazu erstmal XML parsen und bearbeiten, dazu lxml docu durcharbeiten. Mit kleinen lokalen beispielen. (gibts dazu auch ein tut, die doku ist nicht sonderlich einsteigerfreundlich?)
2b. HTML. dazu lxml.HTMLParser() mit kleinen beispielen testen.

3. scriptteile verheiraten.
http://www.kinderpornos.info
PythonProgger
User
Beiträge: 5
Registriert: Freitag 26. Juni 2009, 17:57

Zuerst mal Danke für eure Hilfe :)

@Blackjack...
Und die Fehlermeldung ist doch ziemlich deutlich: `etree.HTMLParser()` erwartet keine Argumente, Du hast aber eines angegeben.
Haha, da bin ich wohl drübergestolpert. Jetzt weiß ich wieder was "Den Wald vor lauter Bäumen nicht mehr sehen" bedeutet.


@Snafu, danke für den Link zum guten alten Wiki. Da bin ich aber froh daß ich doch verstanden habe was ein Parser macht.

@Dill: Ich glaube dass man an kongreten Anwendungen ebenfalls lernen kann. Naja, ich spring halt immer gerne gleich ins kalte Wasser.
Natürlich habe ich schon tagelang diverse Beschreibungen und Einführungsbeispiele durchgearbeitet. Das Problem ist aus meiner Sicht dass die Übungsbeispiele viel zu einfach gestrickt sind und das Zweite ist dass der Großteil der Doku/Beschreibung für Leute geschrieben ist welche schon wissen was der entsprechende Befehl macht.
Bzgl. Aufteilung; wie du es beschrieben hast so mache ich es auch. Zuerst habe ich mich um das Login gekümmert ( Mechanize nahm ich weil es hier im Forum immer wieder empfohlen wurde und anscheinend so ne Art Standardtool ist ). Fürs Parsen habe ich auch stundenlang Doku und Foren durchstöbert. Ich habe dabei für mich rausgefunden dass lxml ein gutes, schnelles und effektives Modul ist. Darum habe ich mich auch für dieses Modul entschieden und die Anderen verworfen.


Zurück zu meinem Code :

Code: Alles auswählen

websitehtmlinhalt = etree.HTMLParser()
Soweit ichs bis jetzt verstanden habe ist die HTML-Seite nun in der Variable "websitehtmlinhalt" geparst und ich kann nun mit dem auslesen von Daten beginnen.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

PythonProgger hat geschrieben:

Code: Alles auswählen

websitehtmlinhalt = etree.HTMLParser()
Soweit ichs bis jetzt verstanden habe ist die HTML-Seite nun in der Variable "websitehtmlinhalt" geparst und ich kann nun mit dem auslesen von Daten beginnen.
Nein, woher soll denn der Parser die Daten haben, die er parsen soll? Du gibst die ihm nicht und er kann ja schwerlich raten was du machen willst.

Was du in ``webseitehtmlinhalt`` hast ist eine Referenz auf ein HTMLParser-Objekt. Das mit ganz sicher kein ``webseitenhtmlinhalt`` ist.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
PythonProgger
User
Beiträge: 5
Registriert: Freitag 26. Juni 2009, 17:57

Also, irgendwie beißt sich die Katze in den eigenen Schwanz. Da bin ich doch wieder bei meinem Anfangproblem.
Ich dachte in "websitehtmlinhalt" ist schon der Inhalt der Seite gespeichert UND gleichzeitig auch noch referenziert???

Mir fehlt anscheinend die Verbindung von der Webseite zum Parser. Wie würde denn dieser Befehl aussehen?


EDIT :

Ich glaub jetzt hab ichs :)

Code: Alles auswählen

websitehtmlinhalt=br.response()

#Verbindung Webseite zu Parser

doc = html.parse(websitehtmlinhalt)
root = doc.getroot()
title = root.cssselect(('head title'))[0]
print '\n-----> head title aus websitehtmlinhalt <-----'
print title.text
Benutzeravatar
snafu
User
Beiträge: 6744
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

PythonProgger hat geschrieben:Mechanize nahm ich weil es hier im Forum immer wieder empfohlen wurde und anscheinend so ne Art Standardtool ist
Es kann IMHO als Standardtool für komplexere Sachen gesehen werden, wenn z.B. irgendwo ein Login nötig ist und man dafür irgendwelche Felder ausfüllen muss. Mechanize kümmert sich dabei auch um den Austausch von Cookies, wenn die Seite prüfen will, ob man tatsächlich noch eingeloggt ist. Für frei zugängliche Seiten reicht aber allemal ein `urllib.urlopen()` aus. Mechanize verrichtet die Arbeit nicht schlechter, aber du nimmst ja auch keinen LKW, wenn du eine Schubkarre Sand transportieren willst. ;) Vor allem, falls du das Skript weitergibst, ist Mechanize hier nur eine unnötige Abhängigkeit.
PythonProgger
User
Beiträge: 5
Registriert: Freitag 26. Juni 2009, 17:57

Ich habs jetzt geschafft die Temperatur aus der Webseite auszulesen.
Ich füg einfach mal den aktuellen Stand ein.

Code: Alles auswählen

import mechanize
import ClientForm
import lxml
import lxml.html
from lxml import html
from lxml import etree
from lxml.html import parse
from lxml.cssselect import CSSSelector 

br = mechanize.Browser()
response = br.open("http://www.bergfex.at/oberoesterreich/wetter/stationen/linz/")
websitehtmlinhalt=br.response()

doc = html.parse(websitehtmlinhalt)
root = doc.getroot()
Temperatur = root.cssselect(('td'))[3]
TemperaturText = Temperatur.text

print TemperaturText
Was mir noch nicht gefällt sind zwei Dinge.
* die Temperatur wird als "22.6°C" ausgegeben.
Da muss ich noch schauen wie ich dieses Sonderzeichen wegbekomme.

* der Eintrag [3] im Ausdruck "Temperatur = root.cssselect(('td'))[3]" sollte nicht fix sein. Da möchte ich noch eine flexiblere Lösung finden. D.h. irgendeine Texterkennung ( falls aus irgend einem Grund auf der Webseite was eingefügt wird und sich dadurch die Stelle ändern würde ).

Für Hinweise wie ich diese zwei "Problemchen" lösen könnte wäre ich sehr dankbar.
Zum ersten Punkt denke ich mal dass das eine Konvertierungssache ist.
Zum zweiten Punkt habe ich noch keine Ahnung, da muss ich noch ein bißchen tiefer in die Materie eindringen :)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

PythonProgger hat geschrieben:* der Eintrag [3] im Ausdruck "Temperatur = root.cssselect(('td'))[3]" sollte nicht fix sein. Da möchte ich noch eine flexiblere Lösung finden. D.h. irgendeine Texterkennung ( falls aus irgend einem Grund auf der Webseite was eingefügt wird und sich dadurch die Stelle ändern würde ).
Du kannst auch CSS-Klassen oder IDs bzw Kindbeziehungen etc. im Selektor angeben, dann ist unwarscheinlicher dass der Index ``3`` sich durch irgendeine kleine Änderung verschiebt.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten