Парсинг HTML в Rust: библиотеки и примеры для веб-скрапинга

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

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

Начать курс

Парсинг HTML в Rust: обзор инструментов и практические примеры

Rust — современный системный язык программирования, который всё чаще используется для создания высокопроизводительных веб-скраперов и парсеров. Благодаря строгой системе типов, безопасности памяти и асинхронным возможностям, Rust идеально подходит для задач, где требуется быстро и надёжно извлекать данные из HTML-документов. В этой статье мы рассмотрим ключевые библиотеки для парсинга HTML на Rust, их особенности и приведём рабочие примеры кода.

Основные библиотеки для парсинга HTML в Rust

Экосистема Rust предлагает несколько зрелых решений для работы с HTML. Наиболее популярными являются:

  • scraper — высокоуровневая библиотека с поддержкой CSS-селекторов, построенная поверх select.rs и html5ever.
  • select.rs — библиотека для извлечения данных из DOM с помощью CSS-селекторов.
  • html5ever — низкоуровневый парсер, соответствующий стандарту HTML5 (используется внутри Servo).
  • quick-xml — быстрый XML/HTML парсер на основе потокового чтения, подходит для простых задач.

Для большинства задач веб-скрапинга рекомендуется scraper, так как он предоставляет удобный API и активную поддержку сообщества.

Установка и настройка

Добавьте зависимость в файл Cargo.toml:

[dependencies]
scraper = "0.20"
reqwest = { version = "0.12", features = ["blocking"] }

Библиотека reqwest используется для HTTP-запросов. Если вы предпочитаете асинхронный подход, используйте reqwest с tokio.

Пример 1: Извлечение заголовков страницы

Напишем простой парсер, который получает заголовок <title> и все заголовки <h1> с веб-страницы:

use scraper::{Html, Selector};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let html = r#"
    <html>
        <head><title>Пример страницы</title></head>
        <body>
            <h1>Первый заголовок</h1>
            <h1>Второй заголовок</h1>
        </body>
    </html>
    "#;

    let document = Html::parse_document(html);

    // Извлекаем title
    let title_selector = Selector::parse("title").unwrap();
    if let Some(title_element) = document.select(&title_selector).next() {
        let title_text = title_element.text().collect::().join("");
        println!("Заголовок страницы: {}", title_text);
    }

    // Извлекаем все h1
    let h1_selector = Selector::parse("h1").unwrap();
    for element in document.select(&h1_selector) {
        let text = element.text().collect::().join("");
        println!("H1: {}", text);
    }

    Ok(())
}

В этом примере мы парсим статический HTML. Для реальных сайтов HTML обычно получают через HTTP-запрос.

Пример 2: Парсинг реального сайта с HTTP-запросом

Теперь используем reqwest для загрузки страницы и извлечения ссылок:

use scraper::{Html, Selector};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let response = reqwest::blocking::get("https://www.rust-lang.org")?;
    let html = response.text()?;

    let document = Html::parse_document(&html);
    let link_selector = Selector::parse("a[href]").unwrap();

    println!("Ссылки на странице:");
    for link in document.select(&link_selector) {
        if let Some(href) = link.value().attr("href") {
            let text = link.text().collect::();
            println!("  Текст: '{}' -> URL: {}", text.trim(), href);
        }
    }

    Ok(())
}

Обратите внимание на метод attr("href") — он позволяет получать значения атрибутов элементов.

Пример 3: Работа с атрибутами и вложенными селекторами

Часто требуется извлечь элементы по более сложным правилам. Например, получить все изображения с классом product-image и их атрибут src:

use scraper::{Html, Selector};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let html = r#"
    <div class="products"                    

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