Парсинг веб-страниц с помощью Rust
В этой статье мы узнаем о парсинге веб-страниц с помощью Rust. Возможно, многие из вас еще не слышали о этом языке, но в этом руководстве мы постепенно изучим Rust. Это руководство будет сосредоточено на парсинге веб-страниц, а затем я расскажу о преимуществах и недостатках использования Rust.
Мы будем парсить этот веб-сайт с использованием двух популярных библиотек Rust - **reqwest**
и **scraper**
. Мы расскажем о этих библиотеках немного позже. По окончании этого руководства у вас будет базовое представление о том, как работает Rust и как его можно использовать для парсинга веб-страниц.
Что такое Rust?
Rust - это высокоуровневый язык программирования, разработанный самой Mozilla. Он создан с основным акцентом на создание программного обеспечения. Он отлично работает, когда речь идет о низкоуровневой манипуляции памятью, подобной указателям
в C и C++. Конкурентные соединения также довольно стабильны в Rust. Несколько компонентов программного обеспечения могут работать независимо и одновременно без излишней нагрузки на сервер.
Обработка ошибок также на высоком уровне, поскольку ошибки конкурентности являются ошибками времени компиляции, а не времени выполнения. Это экономит время, и будет показано правильное сообщение об ошибке.
Этот язык также используется в разработке игр и инструментов на основе блокчейна. Многие крупные компании, такие как AWS, Microsoft и др., уже используют этот язык в своей архитектуре.
Настройка предварительных требований
Предполагается, что вы уже установили Rust и Cargo (менеджер пакетов Rust) на вашем компьютере, и если нет, то вы можете обратиться к этому руководству для получения дальнейших инструкций по установке Rust. Сначала нам нужно создать проект на Rust.
cargo new rust_tutorial
Затем нам нужно установить две библиотеки Rust, которые будут использоваться в ходе этого учебника.
[**_reqwest_**](https://docs.rs/reqwest/latest/reqwest/)
: Она будет использоваться для установления HTTP-соединения с веб-сайтом-хостом.[**_scraper_**](https://docs.rs/scraper/latest/scraper/)
_: _Она будет использоваться для выбора элементов DOM и разбора HTML.
Обе эти библиотеки можно установить, добавив их в файл cargo.toml
.
[dependencies]
reqwest = "0.10.8"
scraper = "0.12.0"
Обе версии 0.10.8
и 0.12.0
являются последними версиями библиотек. Теперь, наконец, вы можете получить к ним доступ в вашем основном файле проекта src/main.rs
.
Что мы парсим?
Всегда лучше решить, что вы хотите спарсить. Мы будем парсить названия и цены отдельных книг с страницы.
Процесс будет довольно простым. Сначала мы проверим Chrome, чтобы определить точное местоположение этих элементов в DOM, а затем мы будем использовать библиотеку scraper
для их парсинга.
Парсинг данных отдельных книг
Давайте спарсим названия книг и цены пошагово. Сначала вам нужно определить местоположение элемента в DOM.
Как вы можете видеть на приведенном выше изображении, название книги хранится внутри атрибута title
тега a
. Теперь давайте посмотрим, где хранится цена.
Цена хранится внутри тега p
с классом price_color
. Теперь давайте напишем код на Rust и извлечем эти данные.
Первый шаг - импортировать все необходимые библиотеки в основной файл src/main.rs
.
use reqwest::Client;
use scraper::{Html, Selector};
С помощью reqwest
мы собираемся установить HTTP-соединение с веб-сайтом-хостом, а с помощью библиотеки scraper
мы собираемся разобрать HTML-контент, который мы получим, сделав GET-запрос через библиотеку reqwest
.
Теперь нам нужно создать клиент, который можно будет использовать для отправки запросов на соединение с помощью reqwest
.
let client = Client::new();
Затем, наконец, мы отправим GET-запрос на наш целевой URL с использованием только что созданного client
.
let mut res = client.get("http://books.toscrape.com/")
.send()
.unwrap();
Здесь мы использовали модификатор mut
, чтобы привязать значение к переменной. Это улучшает читаемость кода, и если вы измените это значение в будущем, вам может потребоваться изменить и другие части кода.
После отправки запроса вы получите ответ в формате HTML. Но вам нужно извлечь эту строку HTML из переменной res
с помощью .text().unwrap()
. .unwrap()
похож на try-catch, где он просит программу предоставить результаты, и если возникнет ошибка, он просит программу остановить выполнение как можно скорее.
let body = res.text().unwrap();
Здесь res.text().unwrap()
вернет строку HTML, и мы сохраняем эту строку в переменной body
.
Теперь у нас есть строка, через которую мы можем извлечь все данные, которые нам нужны. Прежде чем мы будем использовать библиотеку scraper
, нам нужно преобразовать эту строку в объект scraper::Html
с помощью Html::parse_document
.
let document = Html::parse_document(&body);
Теперь этот объект можно использовать для выбора элементов и навигации к нужному элементу.
Сначала давайте создадим селектор для названия книги. Мы собираемся использовать функцию Selector::parse
для создания объекта scraper::Selector
.
let book_title_selector = Selector::parse("h3 > a").unwrap();
Теперь этот объект можно использовать для выбора элементов из HTML-документа. Мы передали h3 > a
в качестве аргументов в функцию parse
. Это CSS-селектор для элементов, которые нас интересуют. h3 > a
означает, что он будет выбирать все теги a
, которые являются дочерними элементами тегов h3
.
Как вы можете видеть на изображении, целевой тег a
является дочерним элементом тега h3
. Поэтому мы использовали h3 > a
в вышеприведенном коде.
Поскольку книг так много, мы будем перебирать их все с помощью цикла for
.
for book_title in document.select(&book_title_selector) {
let title = book_title.text().collect::<Vec<_>>();
println!("Title: {}", title[0]);
}
Метод select
предоставит нам список элементов, которые соответствуют селектору book_title_selector
. Затем мы перебираем этот список, чтобы найти атрибут title
и, наконец, вывести его.
Здесь Vec<_>
представляет собой динамический массив. Это вектор, в котором вы можете получить доступ к любому элементу по его позиции в векторе.
Следующий и последний шаг - извлечение цены.
let book_price_selector = Selector::parse(".price_color").unwrap();
Опять же, мы использовали функцию Selector::parse
для создания объекта scraper::Selector
. Как уже обсуждалось выше, цена хранится внутри класса price_color
. Поэтому мы передали это в качестве CSS-селектора в функцию parse
.
Затем мы снова будем использовать цикл for
, как мы делали выше, чтобы перебрать все элементы цены.
for book_price in document.select(&book_price_selector) {
let price = book_price.text().collect::<Vec<_>>();
println!("Price: {}", price[0]);
}
Как только вы найдете соответствие селектора, он получит текст и выведет его в консоль.
Наконец, мы завершили код, который может извлекать название и цену с целевого URL. Теперь, когда вы сохраните это и запустите код с помощью cargo run
, вы получите вывод, который выглядит примерно так.
Title: A Light in the Attic
Price: £51.77
Title: Tipping the Velvet
Price: £53.74
Title: Soumission
Price: £50.10
Title: Sharp Objects
Price: £47.82
Title: Sapiens: A Brief History of Humankind
Price: £54.23
Title: The Requiem Red
Price: £22.65
Title: The Dirty Little Secrets of Getting Your Dream Job
Price: £33.34
Title: The Coming Woman: A Novel Based on the Life of the Infamous Feminist, Victoria Woodhull
Price: £17.93
Title: The Boys in the Boat: Nine Americans and Their Epic Quest for Gold at the 1936 Berlin Olympics
Price: £22.60
Title: The Black Maria
Price: £52.15
Полный код
Вы можете внести изменения в код, чтобы извлечь другую информацию, такую как рейтинги, изображения книг и т. д. Вы можете использовать ту же технику, сначала осмотрев и нашедя местоположение элемента, а затем извлекая их с помощью функции Selector.
Но пока код будет выглядеть так.
use reqwest::Client;
use scraper::{Html, Selector};
// Создаем нового клиента
let client = Client::new();
// Отправляем GET-запрос на веб-сайт
let mut res = client.get("http://books.toscrape.com/")
.send()
.unwrap();
// Извлекаем HTML из ответа
let body = res.text().unwrap();
// Разбираем HTML в документ
let document = Html::parse_document(&body);
// Создаем селектор для названий книг
let book_title_selector = Selector::parse("h3 > a").unwrap();
// Перебираем названия книг
for book_title in document.select(&book_title_selector) {
let title = book_title.text().collect::<Vec<_>>();
println!("Название: {}", title[0]);
}
// Создаем селектор для цен книг
let book_price_selector = Selector::parse(".price_color").unwrap();
// Перебираем цены книг
for book_price in document.select(&book_price_selector) {
let price = book_price.text().collect::<Vec<_>>();
println!("Цена: {}", price[0]);
}
Преимущества использования Rust
- Rust - эффективный язык программирования, подобный C++. Вы можете создавать сложные игры и программное обеспечение с его помощью.
- Он может обрабатывать большой объем одновременных вызовов, в отличие от Python.
- Rust даже может взаимодействовать с языками программирования, такими как C и Python.
Недостатки использования Rust
- Rust - новый язык, если сравнивать его с Nodejs и Python. Из-за небольшого сообщества начинающим очень сложно решить даже небольшую ошибку.
- Синтаксис Rust не так прост для понимания, как Python или Nodejs. Поэтому становится очень сложно читать и понимать код.
Заключение
Мы узнали, как использовать Rust для парсинга веб-страниц. Используя Rust, вы также можете парсить множество других динамических веб-сайтов. Даже в приведенном выше коде вы можете внести несколько изменений, чтобы парсить изображения и рейтинги. Это наверняка улучшит ваши навыки парсинга веб-страниц с помощью Rust.
Надеюсь, вам понравился этот небольшой учебник, и если да, то пожалуйста, не забудьте поделиться им с друзьями и в социальных сетях.
Дополнительные ресурсы
Вот несколько дополнительных ресурсов, которые могут быть полезными во время вашего путешествия по парсингу веб-страниц: