Was sind die Vor- und Nachteile der führenden Java-HTML-Parser? [geschlossen]

175

Bei der Suche nach SO und Google habe ich festgestellt, dass es einige Java-HTML-Parser gibt, die von verschiedenen Parteien konsequent empfohlen werden. Leider ist es schwierig, Informationen über die Stärken und Schwächen der verschiedenen Bibliotheken zu finden. Ich hoffe, dass einige Leute diese Bibliotheken verglichen haben und teilen können, was sie gelernt haben.

Folgendes habe ich gesehen:

Und wenn es einen großen Parser gibt, den ich vermisst habe, würde ich gerne auch über seine Vor- und Nachteile hören.

Vielen Dank!

Avi Flachs
quelle

Antworten:

223

Allgemeines

Fast alle bekannten HTML-Parser implementieren die W3C-DOM-API (Teil der JAXP-API, Java-API für die XML-Verarbeitung) und bieten Ihnen eine org.w3c.dom.DocumentRückseite, die für die direkte Verwendung durch die JAXP-API bereit ist. Die Hauptunterschiede liegen normalerweise in den Funktionen des betreffenden Parsers. Die meisten Parser sind bis zu einem gewissen Grad verzeihend und nachsichtig mit nicht gut geformtem HTML ("tagsoup"), wie JTidy , NekoHTML , TagSoup und HtmlCleaner . Normalerweise verwenden Sie diese Art von HTML-Parsern, um die HTML-Quelle zu "bereinigen" (z. B. indem Sie die HTML-gültige <br>durch eine XML-gültige ersetzen <br />), damit Sie sie mit der W3C-DOM- und JAXP-API "auf die übliche Weise" durchlaufen können.

Die einzigen, die herausspringen, sind HtmlUnit und Jsoup .

HtmlUnit

HtmlUnit bietet eine vollständig eigene API, mit der Sie sich programmgesteuert wie ein Webbrowser verhalten können . Dh Formularwerte eingeben, auf Elemente klicken, JavaScript aufrufen usw. Es ist viel mehr als nur ein HTML-Parser. Es ist ein echtes "GUI-less Webbrowser" und HTML-Unit-Test-Tool.

Jsoup

Jsoup bietet auch eine vollständig eigene API. Es gibt Ihnen die Möglichkeit, Elemente mit jQuery- ähnlichen CSS-Selektoren auszuwählen, und bietet eine übersichtliche API zum Durchlaufen des HTML-DOM-Baums, um die gewünschten Elemente abzurufen.

Insbesondere das Durchlaufen des HTML-DOM-Baums ist die Hauptstärke von Jsoup. Diejenigen, die mit gearbeitet haben, org.w3c.dom.Documentwissen, wie schmerzhaft es ist, das DOM mithilfe der ausführlichen NodeListund NodeAPIs zu durchlaufen . Es stimmt, XPathmacht das Leben einfacher, aber es ist eine weitere Lernkurve und es kann immer noch ausführlich sein.

Hier ist ein Beispiel, das einen "einfachen" W3C-DOM-Parser wie JTidy in Kombination mit XPath verwendet, um den ersten Absatz Ihrer Frage und die Namen aller Antwortenden zu extrahieren (ich verwende XPath, da ohne diesen Code der Code benötigt wird, um die interessierenden Informationen zu sammeln würde sonst 10-mal so groß werden, ohne Utility- / Helfer-Methoden zu schreiben).

String url = "http://stackoverflow.com/questions/3152138";
Document document = new Tidy().parseDOM(new URL(url).openStream(), null);
XPath xpath = XPathFactory.newInstance().newXPath();
  
Node question = (Node) xpath.compile("//*[@id='question']//*[contains(@class,'post-text')]//p[1]").evaluate(document, XPathConstants.NODE);
System.out.println("Question: " + question.getFirstChild().getNodeValue());

NodeList answerers = (NodeList) xpath.compile("//*[@id='answers']//*[contains(@class,'user-details')]//a[1]").evaluate(document, XPathConstants.NODESET);
for (int i = 0; i < answerers.getLength(); i++) {
    System.out.println("Answerer: " + answerers.item(i).getFirstChild().getNodeValue());
}

Und hier ist ein Beispiel, wie man mit Jsoup genau dasselbe macht:

String url = "http://stackoverflow.com/questions/3152138";
Document document = Jsoup.connect(url).get();

Element question = document.select("#question .post-text p").first();
System.out.println("Question: " + question.text());

Elements answerers = document.select("#answers .user-details a");
for (Element answerer : answerers) {
    System.out.println("Answerer: " + answerer.text());
}

Sehen Sie den Unterschied? Es ist nicht nur weniger Code, sondern Jsoup ist auch relativ einfach zu verstehen, wenn Sie bereits mäßige Erfahrung mit CSS-Selektoren haben (z. B. durch Entwickeln von Websites und / oder Verwenden von jQuery).

Zusammenfassung

Die Vor- und Nachteile eines jeden sollten jetzt klar genug sein. Wenn Sie nur die Standard-JAXP-API zum Durchlaufen verwenden möchten, wählen Sie die erstgenannte Gruppe von Parsern. Es gibt ziemlich viele von ihnen. Welche Sie auswählen müssen, hängt von den Funktionen ab (wie wird Ihnen die HTML-Bereinigung erleichtert? Gibt es einige Listener / Interceptors und tag-spezifische Bereiniger?) Und von der Robustheit der Bibliothek (wie oft wird sie aktualisiert / gewartet / repariert?). ). Wenn Sie den HTML-Code testen möchten, ist HtmlUnit der richtige Weg. Wenn Sie bestimmte Daten aus dem HTML-Code extrahieren möchten (was mehr als häufig die Anforderungen der realen Welt sind), ist Jsoup der richtige Weg.

BalusC
quelle
Es gibt ein großes Pro / Contra, das hier weggelassen wird: Jericho ist der einzige mir bekannte Parser, mit dem Sie böses HTML manipulieren können, während die Leerzeichenformatierung und die Unrichtigkeit des HTML-Codes (falls vorhanden) erhalten bleiben.
Adam Gent
3
Jsoupist gut. Ich habe versucht, es mit einem anderen Modul zu verbinden, das mit org.w3c.dom.*API funktioniert . Gefunden, dass Jsoup den org.w3c.dom.*Vertrag nicht befolgt
Thamme Gowda
13

Dieser Artikel vergleicht bestimmte Aspekte der folgenden Parser:

  • NekoHTML
  • JTidy
  • TagSoup
  • HtmlCleaner

Es ist keineswegs eine vollständige Zusammenfassung, und es ist aus dem Jahr 2008. Aber Sie können es hilfreich finden.

Matt Solnit
quelle
Dies ist eine reine Linkantwort. Können Sie hier die relevanten Details hinzufügen?
Stellen Sie Monica wieder her - notmaynard
7

Fügen Sie Ihrer Liste den HTML-Parser validator.nu hinzu , eine Implementierung des HTML5-Parsing-Algorithmus in Java.

Positiv zu vermerken ist, dass es speziell für HTML5 entwickelt wurde und das Herzstück des HTML5-Validators bildet. Daher ist es sehr wahrscheinlich, dass das Analyseverhalten zukünftiger Browser mit einem sehr hohen Maß an Genauigkeit übereinstimmt.

Auf der negativen Seite funktioniert das Legacy-Parsing von Browsern nicht genau so, und da HTML5 noch im Entwurf ist, können sich Änderungen ergeben.

In der Praxis betreffen solche Probleme nur dunkle Eckfälle und sind für alle praktischen Zwecke ein ausgezeichneter Parser.

Alohci
quelle
7

Ich fand Jericho HTML Parser sehr gut geschrieben, auf dem neuesten Stand (was viele der Parser nicht sind), keine Abhängigkeiten und einfach zu bedienen.

MJB
quelle
6

Ich werde nur zur @ MJB-Antwort hinzufügen, nachdem ich mit den meisten HTML-Parsing-Bibliotheken in Java gearbeitet habe. Es gibt ein großes Pro / Contra, das weggelassen wird: Parser, die die Formatierung und Unrichtigkeit des HTML-Codes bei der Eingabe und Ausgabe beibehalten.

Das ist der Fall, wenn die meisten Parser beim Ändern des Dokuments Leerzeichen, Kommentare und Unrichtigkeiten des DOM wegblasen, insbesondere wenn es sich um eine XML-ähnliche Bibliothek handelt.

Jericho ist der einzige mir bekannte Parser, mit dem Sie unangenehmes HTML manipulieren können, während die Leerzeichenformatierung und die Unrichtigkeit des HTML-Codes (falls vorhanden) erhalten bleiben.

Adam Gent
quelle
3

Zwei weitere Optionen sind HTMLCleaner und HTMLParser .

Ich habe die meisten Parser hier für ein Crawler- / Datenextraktions-Framework ausprobiert, das ich entwickelt habe. Ich benutze HTMLCleaner für den Großteil der Datenextraktionsarbeit. Dies liegt daran, dass es einen einigermaßen modernen Dialekt von HTML, XHTML, HTML 5 mit Namespaces und DOM unterstützt, sodass es mit der in Java integrierten XPath-Implementierung verwendet werden kann .

Mit HTMLCleaner ist dies viel einfacher als mit einigen anderen Parsern: JSoup unterstützt beispielsweise eine DOM-ähnliche Schnittstelle anstelle von DOM, sodass einige Assemblys erforderlich sind . Jericho hat eine SAX-Line-Schnittstelle, so dass es wieder einige Arbeit erfordert, obwohl Sujit Pal eine gute Beschreibung dafür hat, aber am Ende hat HTMLCleaner einfach besser funktioniert.

Ich verwende auch HTMLParser und Jericho für eine Tabellenextraktionsaufgabe, die Code ersetzt, der mit Perls libhtml-tableextract-perl geschrieben wurde . Ich verwende HTMLParser, um den HTML-Code für die Tabelle zu filtern, und verwende dann Jericho, um ihn zu analysieren. Ich stimme den Kommentaren von MJB und Adam zu, dass Jericho in einigen Fällen gut ist, weil es den zugrunde liegenden HTML-Code beibehält. Es hat eine Art nicht standardmäßige SAX-Schnittstelle, daher ist HTMLCleaner für die XPath-Verarbeitung besser.

Das Parsen von HTML in Java ist ein überraschend schwieriges Problem, da alle Parser anscheinend Probleme mit bestimmten Arten von fehlerhaftem HTML-Inhalt haben.

Mark Butler
quelle