Seite 1 von 1
Schablone auf einen String anlegen
Verfasst: Montag 6. Februar 2006, 17:37
von tiax
Hallo,
ich habe versucht, eine HTML-Seite nach einigen Informationen zu untersuchen und angefangen, es mit einem Parser zu versuchen. Das problem ist allerdings, dass die HTML-Seite nicht valide ist und wohl mit einem Wysiwyg-Editor gemacht worden ist - die Inhalte sind mit dutzenden Tabellen und leeren Zellen und so weiter eingeordnet und das Parsen macht nicht so recht Spaß. Zwischen den einzelnen Informationen steht dann oft auch noch ein <br> oder <b>. Jede Information steckt aber meist in ihrem eigenen "Design-Element", sprich der umgebende HTML-Code ist immer der gleiche. Ich hab mir also überlegt: Man legt ne Schablone an und übernimmt genau das, was in den Lücken steht. Meine ersten Versuche waren wild mit Schleifen durch .splitlines()-bearbeitete Strings und wieder .split('<br'>), also nicht sonderlich elegant.
Im tiefen Hinterkopf klingelte noch eine Glocke: Regexp. Aber man hat schon von so manchem gehört, der ein Problem mit Strings hatte und sich dachte "Hey ich habs, ich nehm einfach Regexp!" und sodann hatte er zum einen ein Problem mit Strings und zum anderen eines mit Regexp.
Bevor ich mich jetzt also in die wirren der Fingerbrechenden Regexp-Syntax vorwage, wollte ich fragen, ob das eine intelligente Idee ist oder ob die wirklich praktische Methode vielleicht wo ganz anders liegt. Wie wäre sowas denn am besten zu bewerkstelligen?
Verfasst: Montag 6. Februar 2006, 17:43
von modelnine
Wie wärs mit:
http://www.python.org/doc/2.4.2/lib/module-htmllib.html
? Ich hab damit schon relativ einfach Inhalte aus Webseiten rauspulen können. Wenn Du ein Beispiel brauchst sag es, ich schreib gern schnell eins zusammen wenn ich heute abend wieder zu Hause bin.
--- Heiko.
Verfasst: Montag 6. Februar 2006, 17:58
von tiax
Genau mit dem Modul hatte ich schon ein wenig rumgespielt (ohne jetzt aber was abzuspeichern, weils nicht funktioniert hat - wie gesagt, eigener Versuch war mit String-Manipulation), kam aber nicht so wirklich auf einen grünen Zweig damit
Zu analysieren wären Strings (
wie etwa hier)
Code: Alles auswählen
<td bgcolor="#2A2A2A" align="right"><font color="CCCCCC">8.938 <br>6.857 </td>
oder
Code: Alles auswählen
<td bgcolor="#1A1A1A" align="right">
<font color="#CCCCCC">Zielbasis <b>Exosphaere 13x113x7</b> </br>von [DN] Himmelskaiser
</td>
damit hatte ich nicht so viel Freude. Ich bin mir nicht sicher gewesen, ob das wirklich geeignet ist, vor allem bei einigen HTML-Fehlern
Verfasst: Montag 6. Februar 2006, 18:06
von modelnine
htmllib ist sehr vergebend bei Fehlern. Und, ja, es ist definitiv dazu geeignet sowas zu parsen.
Wie gesagt, ich schreib Dir heute abend mal ein kleines Beispielprogramm dafür.
--- Heiko.
Verfasst: Montag 6. Februar 2006, 18:13
von tiax
Gut, dann hatte ich wohl die falsche Herangehensweise, aber mit einem Beispiel werde ich wohl in der Lage sein, den richtigen Einstieg zu finden, danke sehr. Ich warte also artig darauf und werde damit dann versuchen, mein Projekt voranzutreiben
Verfasst: Montag 6. Februar 2006, 21:58
von modelnine
Hier ein Beispiel welches den Inhalt des <b>-Tags aus dem <td> im zweiten Beispiel ausliest:
Code: Alles auswählen
# -*- coding: iso-8859-15 -*-
import HTMLParser
STATE_NONE, STATE_SPECIAL_TD, STATE_BCONTENT = range(3)
class MeinParser(HTMLParser.HTMLParser):
def __init__(self):
HTMLParser.HTMLParser.__init__(self)
self._data = []
self._state = 0
def handle_starttag(self,tag,attrs):
attrs = dict(attrs)
if self._state == STATE_NONE:
if tag == "td":
if ( attrs.get("bgcolor",None) == "#1A1A1A" and
attrs.get("align",None) == "right" ):
self._state = STATE_SPECIAL_TD
elif self._state == STATE_SPECIAL_TD:
if tag == "b":
self._state = STATE_BCONTENT
elif self._state == STATE_BCONTENT:
pass
def handle_endtag(self,tag):
if self._state == STATE_NONE:
pass
elif self._state == STATE_SPECIAL_TD:
if tag == "td":
self._state = STATE_NONE
elif self._state == STATE_BCONTENT:
if tag == "b":
self._state = STATE_SPECIAL_TD
print "Inhalt des B-Tags in speziellem td:", \
repr(u"".join(self._data))
self._data = []
def handle_data(self,data):
if self._state == STATE_NONE:
pass
elif self._state == STATE_SPECIAL_TD:
pass
elif self._state == STATE_BCONTENT:
self._data.append(data)
def handle_charref(self,name):
if self._state == STATE_NONE:
pass
elif self._state == STATE_SPECIAL_TD:
pass
elif self._state == STATE_BCONTENT:
self._data.append(unichr(int(name[1:])))
def handle_entityref(self,name):
if self._state == STATE_NONE:
pass
elif self._state == STATE_SPECIAL_TD:
pass
elif self._state == STATE_BCONTENT:
self._data.append(htmlentitydefs.name2codepoint[name])
data = """
<td bgcolor="#1A1A1A" align="right">
<font color="#CCCCCC">Zielbasis <b>Exosphaere 13x113x7</b> </br>von [DN] Himmelskaiser
</td>
"""
x = MeinParser()
x.feed(data)
x.close()
Das ganze ist im Endeffekt eine state-machine, die vom tokenizer (HTMLParser.HTMLParser) mit aufrufen gefüttert wird. Du kannst dem im Endeffekt beliebig komplex machen, mußt Dir nur darüber im klaren sein wann was aufgerufen wird. Wenn Du dann den Inhalt eines bestimmten Tags ausgelesen hast kannst Du diesen mit Regexes weiterbearbeiten.
Hoffe das hilft!
--- Heiko.
Verfasst: Dienstag 7. Februar 2006, 07:39
von jens
Zum HTMLParser stehen bestimmt noch einige Beispiele hier im Forum! Also einfach mal nach suchen

Re: Schablone auf einen String anlegen
Verfasst: Dienstag 7. Februar 2006, 09:32
von gerold
tiax hat geschrieben:ich habe versucht, eine HTML-Seite nach einigen Informationen zu untersuchen und angefangen, es mit einem Parser zu versuchen. Das problem ist allerdings, dass die HTML-Seite nicht valide ist
Hi tiax!
Ich habe noch nicht versucht, mit BeautifulSoup eine nicht valide HTML-Seite zu parsen. Falls es funktioniert, gibt es kaum eine einfachere Möglichkeit, eine HTML-Seite zu parsen.
Siehe:
http://www.python-forum.de/viewtopic.php?t=4664
mfg
Gerold

Verfasst: Mittwoch 8. Februar 2006, 10:55
von tiax
Hi,
danke für eure Bemühungen, ich kam jedoch nicht so gut zurecht mit den Parsern, am Ende habe ich doch wieder an den Strings rumbauen müssen, nachdem ich geparsed habe.
Das Problem habe ich jetzt aber mit Regexp gelöst, nachdem ich mir das Howto dazu nochmal angeschaut habe.
War nicht schwer, gereicht haben 3 Ausdrücke:
startregexp = compile(r'Startbasis <b> (.+)</b></br> von ?(\[.+\])? ?(.+) ')
zielregexp = compile(r'Zielbasis <b> (.+)</b> </br>von ?(\[.+\])? ?(.+) ')
uhrzeitregexp = compile(r'Zeit <b>(\d+.\d+.\d+) (\d+:\d+:\d+.*)</b>')
Mit startregexp.search(ganzerhtmlinhalt).groups() kriegt man dann ein Tuple in dem alles schön drin steht. Ist vielleicht nicht so effizient, jedoch wird das Script weder häufig ausgeführt noch sind die Berichte besonders lang.