답변:
거의 모든 알려진 HTML 파서는 W3C DOM API (JAXP API의 일부, Java 처리를위한 Java API)를 구현하고 JAXP API에서 org.w3c.dom.Document
직접 사용할 수있는 지원을 제공합니다 . 주요 차이점은 일반적으로 해당 파서의 기능에서 찾을 수 있습니다. 대부분의 파서는 JTidy , NekoHTML , TagSoup 및 HtmlCleaner 와 같이 잘 구성되지 않은 HTML ( "tagsoup")을 어느 정도 용서하고 관대 합니다. 일반적으로 이러한 종류의 HTML 파서를 사용하여 HTML 소스를 "정돈"합니다 (예 : HTML-valid <br>
를 XML-valid로 교체)<br />
) W3C DOM 및 JAXP API를 사용하여 "일반적인 방법"으로 트래버스 할 수 있습니다.
튀어 나오는 유일한 것은 HtmlUnit 과 Jsoup 입니다.
HtmlUnit 은 완전히 고유 한 API를 제공하므로 웹 브라우저처럼 프로그래밍 방식으로 작동 할 수 있습니다. 즉, 양식 값을 입력하고 요소를 클릭하고 JavaScript를 호출합니다. HTML 파서 그 자체가 아닙니다. 실제 "GUI-less 웹 브라우저"및 HTML 단위 테스트 도구입니다.
Jsoup 은 또한 완전히 고유 한 API를 제공합니다. jQuery 와 같은 CSS 선택기를 사용하여 요소를 선택할 수 있으며 HTML DOM 트리를 탐색하여 관심있는 요소를 가져 오는 매끄러운 API를 제공합니다.
특히 HTML DOM 트리의 통과는 Jsoup의 주요 강점입니다. 함께 일한 사람들 org.w3c.dom.Document
은 verbose NodeList
와 Node
API를 사용하여 DOM을 통과하는 것이 얼마나 고통 스러운지 알고 있습니다. 진실,XPath
인생이 더 쉬워 지지만 여전히 또 다른 학습 곡선이며 여전히 장황 할 수 있습니다.
다음은 XPath와 함께 JTidy와 같은 "일반"W3C DOM 파서를 사용하여 질문의 첫 번째 단락과 모든 응답자의 이름을 추출하는 예제입니다 (관심없는 정보를 수집하는 데 코드가 필요했기 때문에 XPath를 사용하고 있습니다) 그렇지 않으면 유틸리티 / 도우미 메소드를 작성하지 않고 10 배 커질 것입니다.
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());
}
다음은 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());
}
차이점이 보입니까? 코드가 적을뿐만 아니라 웹 사이트 개발 및 / 또는 jQuery 사용과 같은 CSS 선택기에 익숙한 경험이 있다면 Jsoup도 비교적 쉽게 파악할 수 있습니다.
각각의 장단점은 이제 충분히 명확해야합니다. 표준 JAXP API를 사용하여 트래버스하려면 먼저 언급 한 파서 그룹으로 이동하십시오. 꽤 많이 있습니다. 선택할 수있는 기능 (제공되는 HTML 정리가 쉬워 집니까? 리스너 / 인터셉터 및 태그 별 클리너가 있습니까?)과 라이브러리의 견고성 (얼마나 자주 업데이트 / 유지 보수 / 고정됩니까?) ). HTML을 단위 테스트하려면 HtmlUnit을 사용하십시오. 실제 요구 사항보다 더 많은 HTML에서 특정 데이터를 추출하려면 Jsoup을 사용하는 것이 좋습니다.
Jsoup
좋습니다. org.w3c.dom.*
API 와 작동하는 다른 모듈과 인터페이스하려고했습니다 . Jsoup이 org.w3c.dom.*
계약을 준수하지 않음을 발견했습니다
이 기사 는 다음 파서의 특정 측면을 비교합니다.
완전한 요약은 아니며 2008 년부터 작성된 것이지만 도움이 될 수도 있습니다.
validator.nu HTML 파서 추가 목록에 자바에서 HTML5 구문 분석 알고리즘의 구현을.
또한 HTML5와 HTML5 유효성 검사기의 핵심에 맞게 특별히 설계되었으므로 향후 브라우저의 구문 분석 동작을 매우 정확하게 일치시킬 가능성이 높습니다.
빼기 측면에서는 브라우저의 기존 구문 분석이 이와 똑같이 작동하지 않으며 HTML5가 아직 초안이므로 변경 될 수 있습니다.
실제로 이러한 문제는 모호한 경우에만 영향을 미치며 모든 실제적인 목적을 위해 훌륭한 파서입니다.
다른 두 가지 옵션은 HTMLCleaner 및 HTMLParser 입니다.
필자가 개발하고있는 크롤러 / 데이터 추출 프레임 워크에 대해 대부분의 파서를 시도했습니다. 대량의 데이터 추출 작업에 HTMLCleaner를 사용합니다. 네임 스페이스를 사용하여 상당히 현대적인 HTML, XHTML, HTML 5의 방언을 지원하고 DOM을 지원하므로 Java의 내장 XPath 구현과 함께 사용할 수 있기 때문입니다 .
예를 들어 JSoup은 DOM보다는 인터페이스와 같은 DOM을 지원하므로 일부 어셈블리가 필요합니다 . 예를 들어 JSoup은 다른 파서보다 HTMLCleaner를 사용하여 훨씬 쉽게 수행 할 수 있습니다. Jericho에는 SAX 라인 인터페이스가 있으므로 Sujit Pal이이를 수행하는 방법에 대해 잘 설명 했지만 결국 HTMLCleaner가 더 잘 작동했지만 약간의 작업이 필요합니다 .
또한 테이블 추출 작업에 HTMLParser와 Jericho를 사용하는데 Perl의 libhtml-tableextract-perl을 사용하여 작성된 일부 코드를 대체했습니다 . HTMLParser를 사용하여 테이블의 HTML을 필터링 한 다음 Jericho를 사용하여 구문 분석합니다. 나는 Jericho가 기본 HTML을 보존하기 때문에 좋은 경우가 있다는 MJB와 Adam의 의견에 동의합니다. 비표준 SAX 인터페이스가 있으므로 XPath 처리에는 HTMLCleaner가 더 좋습니다.
Java에서 HTML을 파싱하는 것은 모든 파서가 특정 유형의 잘못된 HTML 컨텐츠에 대해 어려움을 겪고 있기 때문에 놀랍도록 어려운 문제입니다.