Jakie są wady i zalety wiodących parserów Java HTML? [Zamknięte]

175

Przeszukując SO i Google, odkryłem, że istnieje kilka parserów Java HTML, które są konsekwentnie zalecane przez różne strony. Niestety ciężko jest znaleźć jakiekolwiek informacje o mocnych i słabych stronach różnych bibliotek. Mam nadzieję, że niektórzy ludzie poświęcili trochę czasu na porównanie tych bibliotek i podzielą się tym, czego się nauczyli.

Oto co widziałem:

A jeśli jest jakiś główny parser, którego przegapiłem, chciałbym również usłyszeć o jego zaletach i wadach.

Dzięki!

Avi Flax
źródło

Odpowiedzi:

223

Generał

Prawie wszystkie znane parsery HTML implementują W3C DOM API (część JAXP API, Java API do przetwarzania XML) i zapewniają org.w3c.dom.Documentwsparcie, które jest gotowe do bezpośredniego użycia przez JAXP API. Główne różnice można zwykle znaleźć w funkcjach danego parsera. Większość parserów jest do pewnego stopnia wybaczająca i pobłażliwa w przypadku źle sformułowanego HTML („tagsoup”), takiego jak JTidy , NekoHTML , TagSoup i HtmlCleaner . Zwykle używasz tego rodzaju parserów HTML do "porządkowania" źródła HTML (np. Zastępując HTML-valid <br>przez XML-valid<br /> ), tak abyś mógł go przechodzić "w zwykły sposób" używając W3C DOM i JAXP API.

Jedynymi, które wyskakuje są HtmlUnit i Jsoup .

HtmlUnit

HtmlUnit zapewnia całkowicie własne API, które daje możliwość programowego działania jak przeglądarka internetowa. To znaczy wprowadzanie wartości formularzy, klikanie elementów, wywoływanie JavaScript itp. To znacznie więcej niż sam parser HTML. To prawdziwa "przeglądarka internetowa bez GUI" i narzędzie do testowania jednostek HTML.

Jsoup

Jsoup zapewnia również całkowicie własne API. To daje możliwość wyboru elementów przy użyciu jQuery -Jak selektorów CSS i dostarcza API zręczny przemierzać drzewo HTML DOM, aby elementy zainteresowania.

W szczególności przechodzenie przez drzewo HTML DOM jest główną zaletą Jsoup. Ci, z którymi pracowali, org.w3c.dom.Documentwiedzą, jak piekielnie bolesne jest przechodzenie przez DOM przy użyciu funkcji gadatliwych NodeListi NodeAPI. To prawda, XPathsprawia , że życie jest łatwiejsze, ale nadal jest to kolejna krzywa uczenia się i może się okazać, że nadal będzie gadatliwa.

Oto przykład, który używa "zwykłego" parsera W3C DOM takiego jak JTidy w połączeniu z XPath w celu wyodrębnienia pierwszego akapitu twojego pytania i nazw wszystkich odpowiadających (używam XPath ponieważ bez niego kod potrzebny do zebrania interesujących informacji w przeciwnym razie urósłby 10 razy większy, bez pisania narzędzi / metod pomocniczych).

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());
}

A oto przykład, jak zrobić dokładnie to samo z Jsoup:

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());
}

Czy widzisz różnicę? To nie tylko mniej kodu, ale Jsoup jest również stosunkowo łatwy do zrozumienia, jeśli masz już umiarkowane doświadczenie z selektorami CSS (np. Tworząc strony internetowe i / lub używając jQuery).

Podsumowanie

Wady i zalety każdego z nich powinny być teraz wystarczająco jasne. Jeśli chcesz tylko skorzystać ze standardowego interfejsu API JAXP, aby go przejść, przejdź do pierwszej wspomnianej grupy parserów. Jest ich całkiem sporo . Który z nich należy wybrać, zależy od funkcji, które zapewnia (w jaki sposób czyszczenie HTML jest dla Ciebie łatwe? Czy są jakieś nasłuchiwacze / przechwytywacze i programy czyszczące specyficzne dla tagów?) Oraz solidność biblioteki (jak często jest aktualizowana / utrzymywana / naprawiana? ). Jeśli lubisz testować jednostkowo HTML, najlepszym rozwiązaniem jest HtmlUnit. Jeśli chcesz wyodrębnić określone dane z HTML (co jest często wymaganiem w świecie rzeczywistym), Jsoup jest najlepszym rozwiązaniem.

BalusC
źródło
Pominięto tutaj ogromną zaletę / wadę: Jericho jest jedynym parserem, jaki znam, który pozwala na manipulowanie nieprzyjemnym kodem HTML, zachowując jednocześnie formatowanie białych znaków i niepoprawność HTML (jeśli istnieje).
Adam Gent
3
Jsoupjest dobry. Próbowałem połączyć go z innym modułem, który współpracuje z org.w3c.dom.*API. Okazało się, że Jsoup nie przestrzega org.w3c.dom.*kontraktu
Thamme Gowda
13

W tym artykule porównano niektóre aspekty następujących parserów:

  • NekoHTML
  • JTidy
  • TagSoup
  • HtmlCleaner

W żadnym wypadku nie jest to pełne podsumowanie i pochodzi z 2008 roku. Może się jednak okazać pomocne.

Matt Solnit
źródło
To jest odpowiedź zawierająca tylko łącze. Czy możesz dodać tutaj stosowne szczegóły?
Przywróć Monikę - notmaynard
7

Dodaj analizator HTML validator.nu do listy analizator , implementację algorytmu parsowania HTML5 w Javie.

Z drugiej strony, jest specjalnie zaprojektowany, aby dopasować się do HTML5 i jest sercem walidatora HTML5, więc jest bardzo prawdopodobne, że będzie pasował do przyszłego zachowania parsowania przeglądarki z bardzo wysokim stopniem dokładności.

Z drugiej strony, żadna ze starszych przeglądarek nie działa dokładnie w ten sposób, a ponieważ HTML5 jest nadal w wersji roboczej, może ulec zmianie.

W praktyce takie problemy dotyczą tylko niejasnych przypadków narożnych i ze względów praktycznych są doskonałym parserem.

Alohci
źródło
7

Zauważyłem, że Jericho HTML Parser jest bardzo dobrze napisany, aktualizowany (co nie jest dla wielu parserów), nie zawiera żadnych zależności i jest łatwy w użyciu.

MJB
źródło
6

Po prostu dodam do odpowiedzi @MJB po pracy z większością bibliotek parsujących HTML w Javie, jest ogromna zaleta / wada, która jest pomijana: parsery, które zachowują formatowanie i niepoprawność HTML na wejściu i wyjściu.

To jest większość parserów, kiedy zmieniasz dokument, usunie spacje, komentarze i niepoprawność DOM, szczególnie jeśli są to biblioteki podobne do XML.

Jericho to jedyny parser, jaki znam, który pozwala na manipulowanie nieprzyjemnym kodem HTML, zachowując jednocześnie formatowanie białych znaków i niepoprawność HTML (jeśli istnieje).

Adam Gent
źródło
3

Dwie inne opcje to HTMLCleaner i HTMLParser .

Wypróbowałem większość parserów tutaj dla platformy przeszukiwacza / wyodrębniania danych, którą opracowałem. Używam HTMLCleaner do większości prac związanych z wyodrębnianiem danych. Dzieje się tak, ponieważ obsługuje dość nowoczesny dialekt HTML, XHTML, HTML 5 z przestrzeniami nazw i obsługuje DOM, więc można go używać z wbudowaną implementacją Javy w XPath .

Dużo łatwiej jest to zrobić z HTMLCleaner niż niektórymi innymi parserami: na przykład JSoup obsługuje interfejs podobny do DOM, a nie DOM, więc wymagany jest pewien montaż . Jericho ma interfejs linii SAX, więc znowu wymaga to trochę pracy, chociaż Sujit Pal ma dobry opis, jak to zrobić, ale ostatecznie HTMLCleaner po prostu działał lepiej.

Używam również HTMLParser i Jericho do zadania ekstrakcji tabeli, które zastąpiło kod napisany przy użyciu libhtml-tableextract-perl Perla . Używam HTMLParser do filtrowania kodu HTML dla tabeli, a następnie używam Jericho, aby go przeanalizować. Zgadzam się z komentarzami MJB i Adama, że ​​Jericho jest dobre w niektórych przypadkach, ponieważ zachowuje podstawowy HTML. Ma rodzaj niestandardowego interfejsu SAX, więc do przetwarzania XPath lepiej jest HTMLCleaner.

Przetwarzanie kodu HTML w Javie jest zaskakująco trudnym problemem, ponieważ wydaje się, że wszystkie parsery mają problemy z niektórymi typami źle sformatowanej zawartości HTML.

Mark Butler
źródło