Парсинг HTML в Kotlin: jsoup, ktor, khtml и другие инструменты

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Парсинг HTML в Kotlin: Полное руководство по инструментам и библиотекам

Парсинг HTML (извлечение данных из веб-страниц) — одна из ключевых задач при создании парсеров, анализаторов контента или интеграции внешних данных. В экосистеме Kotlin существует несколько мощных библиотек, которые позволяют эффективно работать с HTML. В этой статье мы подробно разберём лучшие инструменты, их особенности и приведём практические примеры кода.

1. jsoup — стандарт де-факто для парсинга HTML

jsoup — это самая популярная Java-библиотека для работы с HTML, которая отлично работает и в Kotlin. Она предоставляет удобный API для загрузки, разбора и извлечения данных из HTML-документов.

Основные возможности:

  • Загрузка HTML из URL, файла или строки
  • Поддержка CSS-селекторов для поиска элементов
  • Очистка HTML от нежелательных тегов
  • Модификация DOM-дерева

Пример использования jsoup в Kotlin:

import org.jsoup.Jsoup
import org.jsoup.nodes.Document

fun main() {
    // Загружаем HTML-документ
    val doc: Document = Jsoup.connect("https://example.com").get()
    
    // Извлекаем заголовок страницы
    val title: String = doc.title()
    println("Заголовок: $title")
    
    // Ищем все ссылки на странице
    val links = doc.select("a[href]")
    links.forEach { link ->
        val href = link.attr("href")
        val text = link.text()
        println("Ссылка: $text -> $href")
    }
    
    // Извлекаем текст из определенного блока
    val content = doc.select("div.content").text()
    println("Контент: $content")
    
    // Работа с формами
    val form = doc.select("form").first()
    form?.select("input")?.forEach { input ->
        println("Поле: ${input.attr("name")} = ${input.attr("value")}")
    }
}

2. Ktor Client + khtml — современный Kotlin-стек

Ktor Client — это асинхронный HTTP-клиент для Kotlin, который отлично сочетается с библиотекой khtml (Kotlin HTML parser). Вместе они образуют мощный инструмент для веб-скрапинга.

Преимущества подхода:

  • Нативная поддержка корутин (suspend функции)
  • Асинхронная загрузка страниц
  • Гибкая настройка HTTP-запросов
  • Поддержка cookies, сессий и прокси

Пример с Ktor Client и khtml:

import io.ktor.client.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import kotlinx.coroutines.runBlocking
import org.jsoup.Jsoup

suspend fun fetchAndParse(url: String) {
    val client = HttpClient()
    
    try {
        // Асинхронная загрузка HTML
        val response: HttpResponse = client.get(url)
        val html: String = response.bodyAsText()
        
        // Парсинг с помощью jsoup
        val doc = Jsoup.parse(html)
        val headlines = doc.select("h2, h3").map { it.text() }
        
        println("Заголовки на странице:")
        headlines.forEach { println("- $it") }
        
    } catch (e: Exception) {
        println("Ошибка при загрузке: ${e.message}")
    } finally {
        client.close()
    }
}

fun main() = runBlocking {
    fetchAndParse("https://kotlinlang.org")
}

3. Selenium WebDriver — для динамических страниц

Если сайт активно использует JavaScript для рендеринга контента, вам понадобится Selenium WebDriver. Он запускает настоящий браузер и позволяет взаимодействовать с динамическими элементами.

Пример с Selenium в Kotlin:

import org.openqa.selenium.By
import org.openqa.selenium.WebDriver
import org.openqa.selenium.chrome.ChromeDriver
import org.openqa.selenium.chrome.ChromeOptions

fun scrapeDynamicPage() {
    val options = ChromeOptions().apply {
        addArguments("--headless") // Режим без GUI
        addArguments("--disable-gpu")
    }
    
    val driver: WebDriver = ChromeDriver(options)
    
    try {
        driver.get("https://example.com/dynamic")
        
        // Ждём загрузки динамического контента
        Thread.sleep(2000)
        
        // Извлекаем данные
        val elements = driver.findElements(By.cssSelector(".dynamic-content"))
        elements.forEach { element ->
            println("Элемент: ${element.text}")
        }
        
        // Скриншот для отладки
        // val screenshot = (driver as TakesScreenshot).getScreenshotAs(OutputType.FILE)
        
    } finally {
        driver.quit()
    }
}

4. Сравнение библиотек для парсинга HTML

Рекомендаций