Hallo, Phytonier,
ich muss mich leider wieder mal aufgrund eines Problemes an euch wenden. Ich versuche mit html5lib und lxml eine Website zu parsen. Das klappt an sich super, wenn die Seite "sauber" geschreiben wäre. Leider ist manchmal in einer Zeile ein "," zwischen den verschiedenen attributen eines Tags. In dem Fall bringt er mir nen Traceback das "," kein gültiger Wert wäre....
Kann man irgendwas einstellen dass das Komma ignoriert wird?
Hier noch mal der konkrete Kontext...
<form action="/home/index.php?r=23", method="post">
lg Snoda
"Kommafehler" bei html5lib?
Du könntest natürlich mit BeautifulSoup erst einmal den HTML-Text aufräumen.Snoda hat geschrieben:Das klappt an sich super, wenn die Seite "sauber" geschreiben wäre. Leider ist manchmal in einer Zeile ein "," zwischen den verschiedenen attributen eines Tags.
Wo wir beim Thema sind, das habe ich kürzlich entdeckt: http://github.com/adevore/old-beautiful-soup
Parst wesentlich fehlertoleranter als die aktuelle Version von BS.
Parst wesentlich fehlertoleranter als die aktuelle Version von BS.
@Snoda:
lxml selbst ist da ziemlich tolerant:
Ich weiß allerdings nicht, wie es hier aktuell um den HTML5-Parser bestellt ist.
lxml selbst ist da ziemlich tolerant:
Code: Alles auswählen
>>> from lxml import html
>>> root=html.fromstring('<form action="/home/index.php?r=23", method="post">')
>>> html.tostring(root)
'<form action="/home/index.php?r=23" method="post"></form>'
Diesen Satz:
...lese ich so, dass `lxml` von Haus aus keine HTML5-Fähigkeiten mitbringt, was aber dank der Möglichkeit zur Einbindung des Moduls keine große Schwierigkeit darstellen sollte.
http://codespeak.net/lxml/html5parser.htmllxml can benefit from the parsing capabilities of html5lib through the lxml.html.html5parser module.
...lese ich so, dass `lxml` von Haus aus keine HTML5-Fähigkeiten mitbringt, was aber dank der Möglichkeit zur Einbindung des Moduls keine große Schwierigkeit darstellen sollte.
-
- User
- Beiträge: 41
- Registriert: Samstag 20. Juni 2009, 18:12
Grüße[b]
start_with_python[/b]
Lust auf [url=https://www.dropbox.com/referrals/NTE5OTQ5Mjk5]DropBox[/url]? (RefLink)
start_with_python[/b]
Lust auf [url=https://www.dropbox.com/referrals/NTE5OTQ5Mjk5]DropBox[/url]? (RefLink)
Danke für eure Hilfe.
Noch mal das Minimalbeispiel, aber ich denke das Prizip ist den meisten klar...
Die Frage ist jetzt mit welcher Methode ich Performance-optimiert weitermachen soll... html5lib komplett weglassen und nur lxml nutzen? Welche Nachteile würden daraus entstehen?
Noch mal das Minimalbeispiel, aber ich denke das Prizip ist den meisten klar...
Code: Alles auswählen
from html5lib import treebuilders, HTMLParser
parser=HTMLParser(tree=treebuilders.getTreeBuilder('lxml'))
root=parser.parse("<html><body><a href='irgendwas' id='25'")
print root.xpath(".//a")
root=parser.parse("<html><body><a href='irgendwas', id='25'")
print root.xpath(".//a")
Code: Alles auswählen
[<Element a at 16e1360>]
Traceback (most recent call last):
File "C:\Python25\test.py", line 5, in <module>
root=parser.parse("<html><body><a href='irgendwas', id='25'")
File "build\bdist.win32\egg\html5lib\html5parser.py", line 155, in parse
self._parse(stream, innerHTML=False, encoding=encoding)
File "build\bdist.win32\egg\html5lib\html5parser.py", line 130, in _parse
method(token["name"], token["data"])
File "build\bdist.win32\egg\html5lib\html5parser.py", line 316, in processStartTag
self.startTagHandler[name](name, attributes)
File "build\bdist.win32\egg\html5lib\html5parser.py", line 898, in startTagA
self.addFormattingElement(name, attributes)
File "build\bdist.win32\egg\html5lib\html5parser.py", line 772, in addFormattingElement
self.tree.insertElement(name, attributes)
File "build\bdist.win32\egg\html5lib\treebuilders\_base.py", line 246, in insertElementNormal
element.attributes = attributes
File "build\bdist.win32\egg\html5lib\treebuilders\etree.py", line 44, in _setAttributes
self._element.set(key, value)
File "lxml.etree.pyx", line 634, in lxml.etree._Element.set (src/lxml/lxml.etree.c:31548)
File "apihelpers.pxi", line 482, in lxml.etree._setAttributeValue (src/lxml/lxml.etree.c:13849)
File "apihelpers.pxi", line 1417, in lxml.etree._attributeValidOrRaise (src/lxml/lxml.etree.c:21673)
ValueError: Invalid attribute name u','
Hello world!
Das tolle an HTML5 ist ja, das es ein riesigen Regelsatz für das Parsen mitbringt und so versucht, den Kraut- und Rüben-Wuchs zumindest auf Parserseite einzudämmen (Dumm nur, dass so auch die Ersetzungsregeln für "falsches" HTML5 vorgeben sind und nun als Entschuldigung für das Schreiben kaputter Dokumente dienen können ).
Zu der Sache mit dem Komma:
Die Spec sagt folgendes dazu - http://www.w3.org/TR/html5/syntax.html# ... name-state
Demnach ist quasi alles als Attributname erlaubt, was nicht unter Leerstellen, '/', '>' usw. fällt. Damit wäre das ein Bug, der scheint beim Treebuilder zu liegen. (Offensichtlich mag Dein lxml-Treebuilder ',' nicht als Attributnamen.)
Nichtsdestotrotz hat lxml in den neueren Versionen einen html5-Parser integriert (von html5lib), falls Du auf HTML5 bestehst, kannst Du ja mal testen, ob es direkt aus lxml heraus funktioniert (vllt. ist die treebuilder-API hier angepasst worden).
Wenn Du aber tatsächlich auf Performance optimieren willst, bleibt eigentlich nur die reine lxml-Lösung, da der html5lib-Parser hier deutlich schlechter ist. Auch HTML5 betreffend wärst Du erstmal nicht schlechter gestellt, da vom W3C versichert wird, dass HTML5, was sich nur schleichend verbreiten wird (siehe oben), von heutigen "kaputten" HTML-Parsern verarbeitet werden kann.
Grüsse jerch
Zu der Sache mit dem Komma:
Die Spec sagt folgendes dazu - http://www.w3.org/TR/html5/syntax.html# ... name-state
Demnach ist quasi alles als Attributname erlaubt, was nicht unter Leerstellen, '/', '>' usw. fällt. Damit wäre das ein Bug, der scheint beim Treebuilder zu liegen. (Offensichtlich mag Dein lxml-Treebuilder ',' nicht als Attributnamen.)
Ich würde derzeit auf HTML5-Konformität verzichten. Zum einen ist HTML5 sehr neu, selbst unter Browsern nicht bis rudimentär umgesetzt (die meisten neuen Elemente besitzen noch gar keine eigene visuelle Repräsentation, z.B. input-Typen wie date und color). Dasselbe gilt auf Sprachenseite, die verfügbaren HTML5-Bibliotheken sind, sofern überhaupt schon vorhanden, kaum dem Alphastadium entwachsen. Das gilt wohl auch für Python und lxml im Besonderen, da dieses stark auf libxml aufsetzt und es dort keinen erkennbaren Fahrplan in Richtung HMTL5 gibt.Snoda hat geschrieben:Die Frage ist jetzt mit welcher Methode ich Performance-optimiert weitermachen soll... html5lib komplett weglassen und nur lxml nutzen? Welche Nachteile würden daraus entstehen?
Nichtsdestotrotz hat lxml in den neueren Versionen einen html5-Parser integriert (von html5lib), falls Du auf HTML5 bestehst, kannst Du ja mal testen, ob es direkt aus lxml heraus funktioniert (vllt. ist die treebuilder-API hier angepasst worden).
Wenn Du aber tatsächlich auf Performance optimieren willst, bleibt eigentlich nur die reine lxml-Lösung, da der html5lib-Parser hier deutlich schlechter ist. Auch HTML5 betreffend wärst Du erstmal nicht schlechter gestellt, da vom W3C versichert wird, dass HTML5, was sich nur schleichend verbreiten wird (siehe oben), von heutigen "kaputten" HTML-Parsern verarbeitet werden kann.
Grüsse jerch
Man kann's auch selbst filtern, z.B. so:
Besser wäre aber noch, den Verursacher des kaputten HTMLs so lange zu schlagen, bis der wenigstens wohlgeformtes (X)HTML erzeugt - es muss ja noch nicht mal valide sein.
Stefan
Code: Alles auswählen
import re
def filter_attributes(s):
def g(m):
return m[0] + "=" + m[2] if m[1] else m[0]
def f(m):
if m.group(2):
return m.group(1) + " ".join(g(m) for m
in re.findall(r"""([\w:-]+)(?:\s*(=)\s*("[^"]*"|'[^']*'|\S+))?""",
m.group(2))) + m.group(3)
return m.group(0)
return re.sub(r"(<[\S+]\s+)([^.]+)(/?\s*>)|[^<]+", f, s)
print filter_attributes('<a href="http://url", title=abc>so what</a>')
Stefan
So, ich parse jetzt nur noch mit lxml. Anfangs dachte ich lxml hat keinen eigenen Parser, und hier wurde auch immer html5lib empfohlen...
... lxml ist tatsächlich wesentlich performanter und toleranter. Ich bin begeistert
Danke für die guten Tips und frohes Weihnachtsfest euch allen!
LG Snoda
... lxml ist tatsächlich wesentlich performanter und toleranter. Ich bin begeistert
Danke für die guten Tips und frohes Weihnachtsfest euch allen!
LG Snoda
Hello world!