Parsing HTML in Rust: Overview of the Best Libraries and Code Examples
Rust is a systems programming language that is increasingly used for tasks related to HTML parsing. Thanks to its high performance, strong typing, and memory safety, Rust is well-suited for creating fast and reliable web page parsers. In this article, we will look at the main libraries for parsing HTML in Rust, their capabilities, and provide practical code examples.
Why Rust for HTML Parsing?
HTML parsing is a task that requires efficient memory management and robust error handling. Rust provides:
- Zero-cost abstractions — high execution speed
- Safe memory management without a garbage collector
- A powerful type system that prevents errors at compile time
- An active community and many libraries for web scraping
Main Libraries for Parsing HTML in Rust
1. scraper — The Most Popular Library
The scraper library provides a convenient API for navigating the DOM tree using CSS selectors. It is built on top of the html5ever parser, which conforms to HTML5 standards.
Installation:
[dependencies]scraper = "0.18"Example: Extracting all links from a page
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!("Link: {}", href); } }}2. select.rs — Lightweight and Fast Selector
The select.rs library offers a minimalistic interface for working with CSS selectors. It also uses html5ever under the hood but provides lower-level access to the DOM.
Installation:
[dependencies]select = "0.6"Example: Finding all h2 headings
use select::document::Document;use select::predicate::Name;
fn main() { let html = r#" <html> <body> <h2>Heading 1</h2> <h2>Heading 2</h2> <p>Text</p> </body> </html> "#;
let document = Document::from(html); for node in document.find(Name("h2")) { println!("Heading text: {}", node.text()); }}3. html5ever — Low-Level Parser
html5ever is the reference HTML5 parser written in Rust. It forms the basis of most other libraries. If you need maximum control over the parsing process, use it directly.
Example: HTML tokenization
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();}Practical Example: Parsing a Real Website
Let's look at a complete example of parsing a news website using scraper and reqw