Разбор HTML в Java с помощью Jsoup

Разбор HTML в Java с помощью Jsoup

1. обзор

Jsoup - это библиотека Java с открытым исходным кодом, используемая в основном для извлечения данных из HTML. Это также позволяет вам манипулировать и выводить HTML. Он имеет устойчивую линию разработки, отличную документацию, а также гибкий и гибкий API. Jsoup также может быть использован для анализа и сборки XML.

В этом руководстве мы будем использоватьSpring Blog, чтобы проиллюстрировать упражнение по очистке, которое демонстрирует несколько функций jsoup:

  • Загрузка: получение и анализ HTML вDocument

  • Фильтрация: выбор нужных данных вElements и их обход

  • Извлечение: получение атрибутов, текста и HTML узлов

  • Модификация: добавление / редактирование / удаление узлов и редактирование их атрибутов

2. Maven Dependency

Чтобы использовать библиотеку jsoup в своем проекте, добавьте зависимость к вашемуpom.xml:


    org.jsoup
    jsoup
    1.10.2

Вы можете найти последнюю версиюjsoup в репозитории Maven Central.

3. Краткий обзор Jsoup

Jsoup загружает страницу HTML и создает соответствующее дерево DOM. Это дерево работает так же, как DOM в браузере, предлагая методы, аналогичные jQuery и vanilla JavaScript, для выбора, обхода, манипуляции с атрибутами text / HTML / и добавления / удаления элементов.

Если вы знакомы с селекторами на стороне клиента и перемещением / манипулированием DOM, вам будет хорошо знаком jsoup. Проверьте, насколько просто распечатать абзацы страницы:

Document doc = Jsoup.connect("http://example.com").get();
doc.select("p").forEach(System.out::println);

Имейте в виду, что jsoup интерпретирует только HTML - он не интерпретирует JavaScript. Поэтому изменения в DOM, которые обычно происходят после загрузки страницы в браузере с поддержкой JavaScript, не будут видны в jsoup.

4. загрузка

Фаза загрузки включает в себя выборку и анализ HTML вDocument. Jsoup гарантирует синтаксический анализ любого HTML, от самого недействительного до полностью проверенного, как это сделал бы современный браузер. Этого можно добиться, загрузивString,InputStream,File или URL.

Давайте загрузимDocument из URL-адреса блога Spring:

String blogUrl = "https://spring.io/blog";
Document doc = Jsoup.connect(blogUrl).get();

Обратите внимание на методget, он представляет собой HTTP-вызов GET. Вы также можете выполнить HTTP POST с методомpost (или вы можете использоватьmethod, который получает тип метода HTTP в качестве параметра).

Если вам нужно обнаружить ненормальные коды состояния (например, 404), вы должны поймать исключениеHttpStatusException:

try {
   Document doc404 = Jsoup.connect("https://spring.io/will-not-be-found").get();
} catch (HttpStatusException ex) {
   //...
}

Иногда соединение должно быть немного более индивидуальным. Jsoup.connect(…) возвращаетConnection, который позволяет вам, среди прочего, установить пользовательский агент, реферер, тайм-аут соединения, файлы cookie, данные публикации и заголовки:

Connection connection = Jsoup.connect(blogUrl);
connection.userAgent("Mozilla");
connection.timeout(5000);
connection.cookie("cookiename", "val234");
connection.cookie("cookiename", "val234");
connection.referrer("http://google.com");
connection.header("headersecurity", "xyz123");
Document docCustomConn = connection.get();

Поскольку соединение следует свободному интерфейсу, вы можете связать эти методы перед вызовом нужного HTTP-метода:

Document docCustomConn = Jsoup.connect(blogUrl)
  .userAgent("Mozilla")
  .timeout(5000)
  .cookie("cookiename", "val234")
  .cookie("anothercookie", "ilovejsoup")
  .referrer("http://google.com")
  .header("headersecurity", "xyz123")
  .get();

Вы можете узнать больше о настройкахConnection наbrowsing the corresponding Javadoc.

5. фильтрация

Теперь, когда у нас есть HTML, преобразованный вDocument, пришло время перемещаться по нему и искать то, что мы ищем. Именно здесь сходство с jQuery / JavaScript более очевидно, поскольку его селекторы и методы обхода похожи.

5.1. выбирающий

МетодDocumentselect получаетString, представляющий селектор, используя тот же синтаксис селектораas in a CSS or JavaScript, и извлекает соответствующий списокElements. Этот список может быть пустым, но неnull.

Давайте посмотрим на некоторые варианты выбора с помощью методаselect:

Elements links = doc.select("a");
Elements sections = doc.select("section");
Elements logo = doc.select(".spring-logo--container");
Elements pagination = doc.select("#pagination_control");
Elements divsDescendant = doc.select("header div");
Elements divsDirect = doc.select("header > div");

Вы также можете использовать более явные методы, вдохновленные DOM браузера, вместо общегоselect:

Element pag = doc.getElementById("pagination_control");
Elements desktopOnly = doc.getElementsByClass("desktopOnly");

ПосколькуElement является суперклассомDocument, вы можете узнать больше о работе с методами выбора в документации JavadocsDocument иElement.

5.2. Обход

Traversing means navigating across the DOM tree. Jsoup предоставляет методы, которые работают сDocument, с наборомElements, или с конкретнымElement, позволяя вам переходить к родителям, братьям, сестрам или дочерним узлам .

Кроме того, вы можете перейти к первому, последнему и n-му (используя индекс, основанный на 0)Element в набореElements:

Element firstSection = sections.first();
Element lastSection = sections.last();
Element secondSection = sections.get(2);
Elements allParents = firstSection.parents();
Element parent = firstSection.parent();
Elements children = firstSection.children();
Elements siblings = firstSection.siblingElements();

Вы также можете перебирать выборки. Фактически, можно повторить итерацию любого типаElements:

sections.forEach(el -> System.out.println("section: " + el));

Вы можете сделать выбор, ограниченный предыдущим выбором (подвыбор):

Elements sectionParagraphs = firstSection.select(".paragraph");

6. экстрагирование

Теперь мы знаем, как достичь определенных элементов, поэтому пришло время получить их содержимое, а именно их атрибуты, HTML или дочерний текст.

Взгляните на этот пример, который выбирает первую статью из блога и получает дату, текст первого раздела и, наконец, внутренний и внешний HTML:

Element firstArticle = doc.select("article").first();
Element timeElement = firstArticle.select("time").first();
String dateTimeOfFirstArticle = timeElement.attr("datetime");
Element sectionDiv = firstArticle.select("section div").first();
String sectionDivText = sectionDiv.text();
String articleHtml = firstArticle.html();
String outerHtml = firstArticle.outerHtml();

Вот несколько советов, которые следует учитывать при выборе и использовании селекторов:

  • Положитесь на функцию «Просмотр исходного кода» вашего браузера, а не только на DOM страницы, поскольку она могла бы измениться (выбор в консоли браузера может привести к результатам, отличным от jsoup)

  • Know your selectors, их много и всегда хорошо хотя бы увидеть их раньше; освоение селекторов требует времени

  • Use a playground for selectors, чтобы поэкспериментировать с ними (вставьте туда образец HTML)

  • Будьте менее зависимы от изменений страницы: стремитесь к самым маленьким и наименее компрометирующим селекторам (например предпочитаю id. на основании)

7. модифицирующий

Модификация включает в себя настройку атрибутов, текста и HTML элементов, а также добавление и удаление элементов. Это делается для дерева DOM, ранее созданного jsoup -Document.

7.1. Установка атрибутов и внутреннего текста / HTML

Как и в jQuery, методы для установки атрибутов, текста и HTML имеют те же имена, но также получают значение для установки:

  • attr() - устанавливает значения атрибута (создает атрибут, если он не существует)

  • text() - устанавливает внутренний текст элемента, заменяя содержимое

  • html() - устанавливает внутренний HTML элемента, заменяя контент

Давайте посмотрим на быстрый пример этих методов:

timeElement.attr("datetime", "2016-12-16 15:19:54.3");
sectionDiv.text("foo bar");
firstArticle.select("h2").html("
");

7.2. Создание и добавление элементов

Чтобы добавить новый элемент, вам нужно сначала создать его, создав экземплярElement. После созданияElement вы можете добавить его к другомуElement, используя методappendChild. Вновь созданный и добавленныйElement будет вставлен в конец элемента, в котором вызываетсяappendChild:

Element link = new Element(Tag.valueOf("a"), "")
  .text("Checkout this amazing website!")
  .attr("href", "http://example.com")
  .attr("target", "_blank");
firstArticle.appendChild(link);

7.3. Удаление элементов

Чтобы удалить элементы, вам нужно сначала выбрать их и запустить методremove.

Например, давайте удалим все теги<li>, содержащие класс «navbar-link” изDocument,, и все изображения из первой статьи:

doc.select("li.navbar-link").remove();
firstArticle.select("img").remove();

7.4. Преобразование измененного документа в HTML

Наконец, поскольку мы менялиDocument, мы могли бы захотеть проверить нашу работу.

Для этого мы можем исследовать DOM-деревоDocument путем выбора, обхода и извлечения с использованием представленных методов, или мы можем просто извлечь его HTML какString, используя методhtml():

String docHtml = doc.html();

ВыводString представляет собой аккуратный HTML-код.

8. Заключение

Jsoup - отличная библиотека для чистки любой страницы. Если вы используете Java и не нуждаетесь в парсинге через браузер, это необходимо учитывать в библиотеке. Он знаком и прост в использовании, поскольку он использует ваши знания о интерфейсной разработке, а также следует передовым методам и шаблонам проектирования.

Вы можете узнать больше о парсинге веб-страниц с помощью jsoup, изучивjsoup API и прочитавjsoup cookbook.

Исходный код, используемый в этом руководстве, можно найти в папкеGitHub project.