Перейти к основному содержимому

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

· 7 мин. чтения

1. Обзор

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

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

  • Загрузка: извлечение и разбор HTML в документ
  • Фильтрация: выбор нужных данных в Elements и их обход
  • Извлечение: получение атрибутов, текста и HTML узлов
  • Модификация: добавление/редактирование/удаление узлов и редактирование их атрибутов

2. Зависимость от Maven

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

<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.10.2</version>
</dependency>

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

3. Суп с первого взгляда

Jsoup загружает HTML-код страницы и строит соответствующее дерево DOM. Это дерево работает так же, как DOM в браузере, предлагая методы, аналогичные jQuery и ванильному JavaScript, для выбора, перемещения, управления текстом/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 в документ . Jsoup гарантирует синтаксический анализ любого HTML, от самого недействительного до полностью проверенного, как это сделал бы современный браузер. Этого можно добиться, загрузив String , InputStream , File или URL.

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

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

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

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

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

Иногда соединение должно быть немного более индивидуальным. Jsoup.connect(…) возвращает соединение , которое позволяет вам, среди прочего, установить пользовательский агент, реферер, время ожидания соединения, файлы 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();

Вы можете узнать больше о настройках подключения , просмотрев соответствующий Javadoc .

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

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

5.1. Выбор

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

Давайте взглянем на некоторые выборки, используя метод 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 , вы можете узнать больше о работе с методами выбора в документах Document и Element Javadocs.

5.2. Пересечение

Обход означает навигацию по дереву DOM. Jsoup предоставляет методы, которые работают с Document , набором Elements или определенным Element , позволяя вам переходить к родительским, одноуровневым или дочерним элементам узла.

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

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)
  • Знайте свои селекторы, так как их много, и всегда хорошо хотя бы видеть их раньше; освоение селекторов требует времени
  • Используйте игровую площадку для селекторов, чтобы поэкспериментировать с ними (вставьте туда образец HTML)
  • Будьте менее зависимы от изменений страницы: стремитесь к наименьшим и наименее компрометирующим селекторам (например, предпочтение на основе идентификатора).

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("<div><span></span></div>");

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

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

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

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

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

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

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

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

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

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

String docHtml = doc.html();

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

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

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

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

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