Jsoup для Java: Полное руководство по парсингу HTML
1. Что такое Jsoup и зачем он нужен?
Jsoup — это мощная и удобная Java-библиотека с открытым исходным кодом, предназначенная для парсинга (разбора), извлечения данных и манипуляции HTML-документами. Она предоставляет разработчикам чистый и интуитивно понятный API, который позволяет работать с HTML так же легко, как с DOM-деревом в браузере. Если вам когда-либо приходилось писать регулярные выражения для извлечения данных из веб-страниц, вы знаете, насколько это может быть хрупким и трудно поддерживаемым решением. Jsoup решает эту проблему, предлагая надёжный и гибкий инструмент.
Основная задача Jsoup — парсинг HTML. Он может принимать на вход строку, URL-адрес или файл и превращать их в объектную модель документа (DOM). После этого вы можете использовать CSS-селекторы (как в jQuery) или навигацию по DOM-дереву для поиска и извлечения конкретных элементов, их атрибутов и текстового содержимого. Кроме того, Jsoup умеет очищать HTML от потенциально опасных элементов (например, XSS-атак) и модифицировать документ: добавлять, удалять или изменять теги и их содержимое.
Зачем это нужно? Сферы применения Jsoup очень широки: от написания простых парсеров для сбора данных (web scraping) и мониторинга цен до создания сложных систем анализа контента, тестирования веб-приложений и интеграции с CMS. Jsoup — это стандарт де-факто для работы с HTML в мире Java, и его знание является обязательным для любого Java-разработчика, сталкивающегося с веб-технологиями.
2. Установка Jsoup
Jsoup распространяется как JAR-файл, но проще всего подключить его через систему сборки. Ниже приведены команды для Maven и Gradle.
Maven (pom.xml)
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.17.2</version>
</dependency>
Gradle (build.gradle)
implementation 'org.jsoup:jsoup:1.17.2'
Если вы не используете системы сборки, скачайте JAR-файл с официального сайта и добавьте его в classpath вашего проекта.
3. Быстрый старт: минимальный рабочий пример
Давайте напишем простейшую программу, которая загружает главную страницу Google и выводит её заголовок.
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
public class QuickStart {
public static void main(String[] args) throws Exception {
// 1. Загружаем HTML-документ по URL
Document doc = Jsoup.connect("https://www.google.com").get();
// 2. Извлекаем заголовок страницы (содержимое тега <title>)
String title = doc.title();
// 3. Выводим результат
System.out.println("Заголовок страницы: " + title);
}
}
Этот код делает HTTP GET-запрос к указанному URL, парсит полученный HTML и возвращает объект Document. Метод title() — это удобный способ получить содержимое тега <title>. Вывод будет примерно таким: Заголовок страницы: Google.
4. Основные методы и классы Jsoup
Рассмотрим ключевые классы и методы библиотеки. Все примеры предполагают, что вы уже импортировали org.jsoup.Jsoup и org.jsoup.nodes.*.
4.1. Jsoup.connect(String url)
Сигнатура: public static Connection connect(String url)
Что делает: Создаёт новое HTTP-соединение к указанному URL. Возвращает объект Connection, который можно настроить (добавить заголовки, куки, таймауты) и затем выполнить запрос методом get() или post().
// Пример с настройкой
Document doc = Jsoup.connect("https://example.com")
.userAgent("Mozilla/5.0")
.timeout(10000)
.cookie("session", "abc123")
.get();
4.2. Jsoup.parse(String html)
Сигнатура: public static Document parse(String html)
Что делает: Парсит переданную строку, содержащую HTML-код, и возвращает объект Document. Это полезно, когда HTML уже получен (например, из файла или базы данных).
String html = "<html><head><title>Мой сайт</title></head><body><p>Привет!</p></body></html>";
Document doc = Jsoup.parse(html);
System.out.println(doc.title()); // Выведет: Мой сайт
4.3. Document.getElementById(String id)
Сигнатура: public Element getElementById(String id)
Что делает: Находит первый элемент в документе с указанным атрибутом id. Возвращает null, если элемент не найден. Это самый быстрый способ поиска элемента по уникальному идентификатору.
// HTML: <div id="content">Основной контент</div>
Element contentDiv = doc.getElementById("content");
if (contentDiv != null) {
System.out.println(contentDiv.text()); // Выведет: Основной контент
}
4.4. Element.select(String cssQuery)
Сигнатура: public Elements select(String cssQuery)
Что делает: Находит все элементы, соответствующие CSS-селектору. Возвращает объект Elements (список Element). Это самый мощный и гибкий метод для поиска элементов. Поддерживаются все основные CSS-селекторы, а также некоторые расширения Jsoup (например, :contains(text)).
// HTML: <ul class="menu"><li>Главная</li><li class="active">О нас</li></ul>
Elements menuItems = doc.select("ul.menu li");
for (Element item : menuItems) {
System.out.println(item.text());
}
// Более сложный селектор: найти все ссылки внутри div с id "main"
Elements links = doc.select("div#main a[href]");
4.5. Element.text()
Сигнатура: public String text()
Что делает: Извлекает и возвращает объединённый текстовый контент элемента и всех его дочерних элементов. Пробелы и переносы строк нормализуются. Это основной способ получения "чистого" текста без HTML-тегов.
// HTML: <p>Это <strong>важный</strong> текст.</p>
Element paragraph = doc.select("p").first();
String text = paragraph.text();
System.out.println(text); // Выведет: Это важный текст.
4.6. Element.attr(String attributeKey)
Сигнатура: public String attr(String attributeKey)
Что делает: Возвращает значение указанного атрибута элемента. Если атрибут отсутствует, возвращается пустая строка (не null). Чаще всего используется для получения href у ссылок, src у изображений или class.
// HTML: <a href="https://example.com" class="link">Пример</a>
Element link = doc.select("a").first();
String href = link.attr("href"); // "https://example.com"
String cssClass = link.attr("class"); // "link"
4.7. Elements.first() и Elements.last()
Сигнатура: public Element first() / public Element last()
Что делает: Возвращают первый или последний элемент из коллекции Elements. Если коллекция пуста, возвращают null. Это удобно, когда нужно получить только один элемент, не перебирая весь список.
Elements images = doc.select("img");
Element firstImage = images.first();
Element lastImage = images.last();
if (firstImage != null) {
System.out.println("Первое изображение: " + firstImage.attr("src"));
}
4.8. Element.html() и Document.html()
Сигнатура: public String html()
Что делает: Возвращает внутренний HTML-код элемента (все дочерние узлы в виде строки). Для Document возвращает весь HTML-код документа. Это полезно для отладки или когда нужно получить HTML-фрагмент для последующей обработки.
// HTML: <div><p>Текст</p></div>
Element div = doc.select("div").first();
String innerHtml = div.html(); // "<p>Текст</p>"
String outerHtml = div.outerHtml(); // "<div><p>Текст</p></div>"
4.9. Jsoup.parse(File in, String charsetName)
Сигнатура: public static Document parse(File in, String charsetName)
Что делает: Парсит HTML-файл с диска. Параметр charsetName указывает кодировку файла (например, "UTF-8"). Это основной способ для работы с локальными HTML-файлами.
File input = new File("/path/to/myfile.html");
Document doc = Jsoup.parse(input, "UTF-8");
System.out.println(doc.title());
4.10. Jsoup.clean(String bodyHtml, Whitelist whitelist)
Сигнатура: public static String clean(String bodyHtml, Whitelist whitelist)
Что делает: Очищает HTML-строку от тегов и атрибутов, не входящих в "белый список" (Whitelist). Это критически важный метод для защиты от XSS-атак (Cross-Site Scripting) при вставке пользовательского HTML-контента на страницу. Jsoup предоставляет несколько предопределённых списков, например, Whitelist.basic(), Whitelist.simpleText(), Whitelist.relaxed().
String unsafeHtml = "<p>Привет! <script>alert('XSS')</script></p>";
String safeHtml = Jsoup.clean(unsafeHtml, Whitelist.basic());
System.out.println(safeHtml);
// Выведет: <p>Привет! </p> (тег script был удалён)
5. Реальный практический пример: Парсинг новостного сайта
Предположим, мы хотим собрать заголовки и ссылки на статьи с главной страницы новостного сайта (например, lenta.ru). Мы напишем программу, которая:
- Загружает главную страницу.
- Находит все элементы, содержащие заголовки новостей (по CSS-классу).
- Извлекает текст заголовка и ссылку.
- Выводит результаты в читаемом виде.
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
public class NewsParser {
public static void main(String[] args) {
String url = "https://lenta.ru"; // Будьте внимательны: сайты могут меняться
try {
// 1. Загружаем страницу с таймаутом и User-Agent
Document doc = Jsoup.connect(url)
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
.timeout(15000)
.get();
// 2. Находим все элементы с классом "card-mini__title" (актуально для lenta.ru на момент написания)
// В реальности селектор нужно подбирать под конкретный сайт.
Elements newsItems = doc.select(".card-mini__title");
if (newsItems.isEmpty()) {
System.out.println("Не удалось найти новости. Возможно, структура сайта изменилась.");
// Попробуем другой селектор
newsItems = doc.select("a[href*='/news/']");
}
int count = 0;
for (Element item : newsItems) {
// 3. Извлекаем текст заголовка
String title = item.text();
// 4. Извлекаем ссылку. Ищем родительский элемент
Также в библиотеке