Парсинг веб-страниц с помощью 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.
Надеюсь, вам понравился этот небольшой учебник, и если да, то пожалуйста, не забудьте поделиться им с друзьями и в социальных сетях.
Дополнительные ресурсы
Вот несколько дополнительных ресурсов, которые могут быть полезными во время вашего путешествия по парсингу веб-страниц:
