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

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

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

Начать курс

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

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

Почему Rust для парсинга HTML?

Парсинг HTML — задача, требующая эффективной работы с памятью и строгой обработки ошибок. Rust предоставляет:

  • Нулевую стоимость абстракций — высокую скорость выполнения
  • Безопасную работу с памятью без сборщика мусора
  • Мощную систему типов, предотвращающую ошибки на этапе компиляции
  • Активное сообщество и множество библиотек для веб-скрапинга

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

1. scraper — самая популярная библиотека

Библиотека scraper предоставляет удобный API для навигации по DOM-дереву с использованием CSS-селекторов. Она построена на основе парсера html5ever, который соответствует стандартам HTML5.

Установка:

[dependencies]
scraper = "0.18"

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

use scraper::{Html, Selector};

fn main() {
    let html = r#"
        <html>
            <body>
                <a href="https://example.com">Example</a>
                <a href="https://rust-lang.org">Rust</a>
            </body>
        </html>
    "#;

    let document = Html::parse_document(html);
    let selector = Selector::parse("a").unwrap();

    for element in document.select(&selector) {
        if let Some(href) = element.value().attr("href") {
            println!("Ссылка: {}", href);
        }
    }
}

2. select.rs — лёгкий и быстрый селектор

Библиотека select.rs предлагает минималистичный интерфейс для работы с CSS-селекторами. Она также использует html5ever под капотом, но предоставляет более низкоуровневый доступ к DOM.

Установка:

[dependencies]
select = "0.6"

Пример: поиск всех заголовков h2

use select::document::Document;
use select::predicate::Name;

fn main() {
    let html = r#"
        <html>
            <body>
                <h2>Заголовок 1</h2>
                <h2>Заголовок 2</h2>
                <p>Текст</p>
            </body>
        </html>
    "#;

    let document = Document::from(html);
    for node in document.find(Name("h2")) {
        println!("Текст заголовка: {}", node.text());
    }
}

3. html5ever — низкоуровневый парсер

html5ever — это эталонный парсер HTML5, написанный на Rust. Он лежит в основе большинства других библиотек. Если вам нужен максимальный контроль над процессом парсинга, используйте его напрямую.

Пример: токенизация HTML

use html5ever::tendril::TendrilSink;
use html5ever::parse_document;
use markup5ever::{expanded_name, local_name, namespace_url, ns};

fn main() {
    let html = "<p>Hello, Rust!</p>";
    let dom = parse_document(
        std::rc::Rc::new(std::cell::RefCell::new(vec![])),
        Default::default()
    )
    .from_utf8()
    .read_from(&mut html.as_bytes())
    .unwrap();
}

Практический пример: парсинг реального сайта

Рассмотрим полный пример парсинга новостного сайта с использованием scraper и reqwest для HTTP-запросов.

use scraper::{Html, Selector};
use reqwest;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Отправляем GET-запрос
    let body = reqwest::get("https://news.ycombinator.com")
        .await?
        .text()
        .await?;

    // Парсим HTML
    let document = Html::parse_document(&body);                    

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