Парсинг 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);