5 лучших HTML-парсеров на Rust для веб-скрейпинга
Если вы используете Rust, как и я, вам нужен парсер, который быстрый, безопасный и удобный в работе. К счастью, есть несколько отличных библиотек, созданных именно для этого. В этом руководстве я рассмотрю 5 лучших HTML-парсеров на Rust, которые я нашёл для веб-скрейпинга. Я расскажу, чем хорош каждый из них, где у него слабые места и когда его стоит использовать.
Зачем нужен HTML-парсер на Rust
Когда вы загружаете веб-страницу с помощью HTTP-клиента Rust, например reqwest, вы получаете необработанный HTML-контент. Однако HTML непросто читать или обходить с помощью базовых строковых методов. HTML-парсеры позволяют вам:
- Ищите элементы по тегам или CSS-классам
- Переход по связям между родительскими и дочерними элементами
- Извлекать текст или значения атрибутов
- Обрабатывайте битый или некорректно сформированный HTML
Это особенно полезно при скрапинге реальных сайтов, которые не всегда следуют идеальным правилам HTML.
Настройка для тестирования
Прежде чем перейти к отдельным библиотекам, вот пример асинхронной функции на Rust, которую мы используем для получения HTML с тестового сайта:
#[tokio::main]
async fn главная() -> Result<(), Box<dyn std::error::Error>> {
пусть resp = reqwest::получить("https://www.scrapingcourse.com/ecommerce/product/adrienne-trek-jacket/")
.ожидайте?
.текст()
.ожидайте?;
println!("{}", resp);
Ok(())
}
Топ-5 лучших HTML-парсеров на Rust для веб-скрейпинга
Let’s take a closer look at each HTML parser on the list. I’ll show you how they work with real-world HTML and how well they perform.
Scraper — простой и надежный
Scraper Это высокоуровневая библиотека для разбора HTML на Rust. Она построена поверх html5ever и selectors, а значит, работает быстро и рассчитана на обработку неаккуратного реального HTML.
Key Features:
- Интерфейс высокого уровня
- Поддержка CSS-селекторов
- Основано на технологиях реальных браузеров
- Древовидная HTML-структура, похожая на DOM
Плюсы:
- Очень прост в использовании
- Может обрабатывать невалидный или поврежденный HTML
- Активная разработка и поддержка сообщества
- Хорошая документация
Конс:
- Потребляет больше памяти на больших страницах
- Ограниченная поддержка изменения HTML
Пример:
использовать scraper::{Html, Selector};
#[tokio::main]
async fn главная() -> Result<(), Box<dyn std::error::Error>> {
пусть resp = reqwest::получить("https://www.scrapingcourse.com/ecommerce/product/adrienne-trek-jacket/")
.ожидайте?
.текст()
.ожидайте?;
пусть fragment = Html::parse_document(&resp);
пусть selector = Selector::разбор(".price").unwrap();
если пусть Some(element) = fragment.select(&selector).next() {
пусть price = element.текст().collect::<String>();
println!("Price: {}", price);
}
Ok(())
}
Use Case: Лучше всего подходит для большинства проектов веб-скрейпинга, особенно когда важны простота использования и совместимость в реальных условиях.
html5ever — быстрый и низкоуровневый

Html5ever Это быстрый и мощный HTML-парсер, написанный на Rust. Он был создан в рамках проекта браузера Servo. Он не строит полноценное DOM-дерево. Вместо этого он использует модель токенизации, выдавая каждый HTML-элемент в виде токена.
Key Features:
- Соответствует стандарту HTML5
- Очень быстрая обработка
- Используется в браузерных движках вроде Servo
Плюсы:
- Чрезвычайно быстрый и эффективный
- Хорошо обрабатывает некорректный HTML
- Полный контроль над структурой HTML
- Возможна низкоуровневая настройка
Конс:
- Многословный и сложнее в использовании
- Нет представления в виде DOM-дерева
- Требует больше кода для извлечения конкретных данных
Пример:
extern crate html5ever;
использовать html5ever::tendril::TendrilSink;
использовать html5ever::tokenizer::{Tokenizer, TokenSink, Token, TokenSinkResult, StartTag, EndTag, CharacterTokens, TokenizerOpts};
использовать html5ever::tokenizer::BufferQueue;
struct PriceFinder {
inside_price: bool, результат: String,
}
impl TokenSink для PriceFinder {
type Handle = ();
fn process_token(&mut себя, token: Token, _line: u64) -> TokenSinkResult<()> {
match token {
Token::TagToken(tag) => {
если tag.kind == StartTag && tag.name.as_ref() == "p" {
для attr в tag.attrs {
если attr.name.local.as_ref() == "class" && attr.value.as_ref() == "цена" {
себя.inside_price = true;
}
}
} else если tag.kind == EndTag && tag.name.as_ref() == "p" {
себя.inside_price = false;
}
}
Token::CharacterTokens(t) => {
если себя.inside_price {
себя.result.push_str(&t);
}
}
_ => {}
}
TokenSinkResult::Continue
}
}
Use Case: Лучше всего подходит для скрейпинга, где критична производительность, или когда нужен полный контроль.
Select.rs — jQuery-Style Syntax
Select.rs — это еще один мощный HTML-парсер для Rust. Его привычный синтаксис в стиле jQuery упрощает написание и понимание селекторов.
Key Features:
- Поддерживает запросы в стиле CSS и XPath
- Позволяет изменять DOM
- Возвращает чистые форматы вывода, такие как JSON и YAML
Плюсы:
- Синтаксис в стиле jQuery
- Прост для новичков
- Может экспортировать данные в нескольких форматах
- Встроенные функции для поиска и редактирования узлов
Конс:
- Использует больше памяти, чем другие инструменты
- Медленнее некоторых альтернатив на больших документах
Пример:
использовать select::document::Document;
использовать select::predicate::{Class, Name};
#[tokio::main]
async fn главная() -> Result<(), Box<dyn std::error::Error>> {
пусть resp = reqwest::получить("https://www.scrapingcourse.com/ecommerce/product/adrienne-trek-jacket/")
.ожидайте?
.текст()
.ожидайте?;
пусть документ = Document::с сайта(resp.as_str());
если пусть Some(price_node) = document.find(Name("p").и(Class("цена"))).next() {
println!("Price: {}", price_node.текст());
}
Ok(())
}
Use Case: Подходит пользователям, которые предпочитают синтаксис в стиле jQuery и хотят выводить структурированные данные.
Kuchiki — дерево, похожее на DOM
Kuchiki (по-японски «гнилое дерево») — это удобный и интуитивно понятный HTML-парсер, который строит DOM-дерево, как настоящий браузер. Он основан на html5ever, но предоставляет древовидный интерфейс с CSS-селекторами.
Key Features:
- Поддержка дерева DOM
- CSS-селекторы
- Позволяет обходить и модифицировать
Плюсы:
- Очень прост в понимании
- Полная древовидная структура
- Хорошая поддержка селекторов
- Отлично подходит для обхода сложного HTML
Конс:
- Больше не поддерживается активно (архивирован в 2023 году)
- Увеличенный размер бинарного файла из-за обработки дерева
Пример:
использовать kuchiki::parse_html;
использовать kuchiki::traits::*;
#[tokio::main]
async fn главная() -> Result<(), Box<dyn std::error::Error>> {
пусть resp = reqwest::получить("https://www.scrapingcourse.com/ecommerce/product/adrienne-trek-jacket/")
.ожидайте?
.текст()
.ожидайте?;
пусть документ = parse_html().one(resp);
если пусть Ok(price_node) = document.select_first("p.price") {
println!("Price: {}", price_node.text_contents());
}
Ok(())
}
Use Case: Лучше всего подходит для обхода дерева и простых задач с HTML. Для крупных проектов его следует избегать из-за отсутствия поддержки.
Pulldown-Cmark — Markdown в первую очередь
Pulldown-cmark не является HTML-парсером в традиционном смысле. Он предназначен для разбора Markdown, но его можно а��аптировать для некоторых задач парсинга HTML. Он хорошо работает в связке с такими инструментами, как html2md, которые преобразуют HTML в Markdown.
Key Features:
- Pull-парсер для Markdown
- Чрезвычайно низкое потребление памяти
- Может преобразовать HTML → Markdown → затем разобрать текст
Плюсы:
- Сверхлегкий
- Эффективен для больших текстовых файлов
- Полезно, когда нужен только обычный текст
- Прост в использовании
Конс:
- Не является полноценным HTML-парсером
- Не поддерживает CSS-селекторы или DOM
- Для обработки HTML требуются другие crates
Пример:
использовать pulldown_cmark::{Parser, Event};
использовать html2md;
#[tokio::main]
async fn главная() -> Result<(), Box<dyn std::error::Error>> {
пусть resp = reqwest::получить("https://www.scrapingcourse.com/ecommerce/product/adrienne-trek-jacket/")
.ожидайте?
.текст()
.ожидайте?;
пусть markdown = html2md::parse_html(&resp);
пусть parser = Parser::новый(&markdown);
для event в parser {
если пусть Event::Text(text) = event {
если text.contains("$") {
println!("Price: {}", text);
}
}
}
Ok(())
}
Use Case: Отлично подходит для преобразования HTML-контента в Markdown для анализа или отображения.
Performance Benchmark
Мы протестировали каждый парсер на одной и той же веб-странице и той же задаче извлечения данных (извлечение цены товара). Вот средние результаты их работы (меньше — лучше):

These tests were run using criterion.rs on a Ryzen 9 machine. Real-world results may vary.
Когда использовать каждый HTML-парсер

Заключение
Rust has several capable HTML parsers for web scraping. Whether you want high performance, easy syntax, or advanced control, there’s a crate for you. If you’re just getting started, Scraper is a great balance of power and simplicity. If you care about raw performance and have time to write more code, go for html5ever. For structured output and jQuery-style selection, try Select.rs.
И если вы преобразуете контент в Markdown, Pulldown-cmark может удивить вас своей скоростью. Какой бы парсер вы ни выбрали, используйте его вместе с надежные прокси или API для скрапинга например, Bright Data или ScrapingBee. Это поможет вашим скрейперам избегать IP-блокировок и эффективно масштабироваться!

