Использование Rust для парсинга веб-страниц
Web Scraping — это метод извлечения информации с веб-сайтов. Это автоматизированный процесс получения больших объемов данных с веб-сайтов, позволяющий сэкономить время и силы и сделать информацию доступной для различных целей.
В этом посте я покажу, как вы можете использовать Rust для извлечения цитат с веб-сайта.
Преимущества использования Rust для парсинга веб-страниц
- Производительность : Rust — это компилируемый язык со статической типизацией, обеспечивающий высокую производительность, что делает его идеальным выбором для парсинга веб-страниц.
- Параллелизм : Rust предоставляет встроенную поддержку параллелизма, которая упрощает одновременную обработку нескольких запросов, повышая эффективность парсинга веб-страниц.
- Безопасность памяти : Rust предоставляет надежные гарантии безопасности памяти, что помогает предотвратить распространенные ошибки, связанные с памятью, такие как исключения нулевого указателя и переполнение буфера, что делает его более безопасным для очистки веб-страниц.
- Простота в освоении : Rust имеет относительно простой синтаксис, что упрощает его изучение разработчиками по сравнению с другими языками программирования.
- Крутая кривая обучения : хотя синтаксис Rust относительно прост, язык может быть сложным для изучения, особенно для разработчиков, которые плохо знакомы с компилируемыми языками со статической типизацией.
- Ограниченное сообщество : хотя сообщество Rust растет, он все еще не так широко используется, как другие языки программирования, а это означает, что поиск ресурсов и поддержки может быть затруднен.
- Нет встроенной библиотеки веб-скрейпинга : в Rust нет встроенной библиотеки для веб-скрейпинга, а это означает, что разработчикам приходится использовать сторонние библиотеки, что может быть менее удобно.
Теперь мы установим Rust, проверим версию Cargoи установим три библиотеки парсинга веб-страниц, reqwest, scraperи selectчерез интерфейс командной строки.
Установить ржавчину
Чтобы установить Rust, вы можете использовать инструмент Rustup, который является рекомендуемым способом установки Rust. Вы можете запустить следующую команду в своем терминале:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Установить груз
Cargo — это менеджер пакетов для Rust, который устанавливается автоматически при установке Rust. Вы можете проверить, установлен ли Cargo, выполнив следующую команду:
cargo --version
Запустите следующую команду в своем терминале:
cargo new toscrape_quotes
Чтобы установить библиотеки парсинга веб-страниц Rust reqwest, scraperи , вы можете добавить в свой файл selectследующие зависимости :Cargo.toml
# Do not forget to update the dependencies section of your Cargo.toml file
[dependencies]
csv = "1.1"
reqwest = "0.10.8"
scraper = "0.13.0"
select = "0.6.0"
cd toscrape_quotes && cargo install --path .
Давайте сделаем парсинг веб-страниц. А не ___ ли нам?
Toscrape.com — это песочница для веб-скрейпинга для тех, кто хочет заняться подобным делом в области разработки программного обеспечения.
Не привлекая нежелательного внимания со стороны корпоративных юристов корпоративных платформ или организаций, вы можете использовать его в качестве игровой площадки. Да вы не хотите видеть этих людей! Некоторые носят костюмы в паре с Air Jordan 1 Chicago .
Код веб-скрейпинга Rust
extern crate csv;
extern crate reqwest;
extern crate scraper;
use std::error::Error;
use std::fs::File;
use std::time::Duration;
use std::thread::sleep;
use reqwest::Client;
use reqwest::StatusCode;
use scraper::{Html, Selector};
const BASE_URL: &str = "http://quotes.toscrape.com";
const MAX_PAGE: u32 = 5;
const MAX_RETRIES: u32 = 3;
const RETRY_SLEEP_SECONDS: u64 = 2;
struct Quote {
text: String,
author: String,
tags: Vec<String>,
}
fn main() -> Result<(), Box<dyn Error>> {
let client = Client::new().timeout(Duration::from_secs(30)).build()?;
let quotes = get_quotes(&client)?;
write_quotes_to_csv("es)?;
Ok(())
}
fn get_quotes(client: &Client) -> Result<Vec<Quote>, Box<dyn Error>> {
let mut quotes = Vec::new();
for page in 1..=MAX_PAGE {
let html = retry_get(client, &format!("{}/page/{}/", BASE_URL, page))?.text()?;
let fragment = Html::parse_document(&html);
let quote_selector = Selector::parse("span.text").unwrap();
let author_selector = Selector::parse("span > small.author").unwrap();
let tag_selector = Selector::parse("div.tags > a.tag").unwrap();
for quote in fragment.select("e_selector) {
let quote_text = quote.text().collect::<Vec<_>>()[0].trim().to_owned();
let author = quote
.parent()
.unwrap()
.select(&author_selector)
.next()
.unwrap()
.text()
.collect::<Vec<_>>()[0]
.trim()
.to_owned();
let tags = quote
.parent()
.unwrap()
.select(&tag_selector)
.map(|tag| tag.text().collect::<Vec<_>>()[0].trim().to_owned())
.collect::<Vec<_>>();
quotes.push(Quote {
text: quote_text,
author,
tags,
});
}
}
Ok(quotes)
}
fn write_quotes_to_csv(quotes: &[Quote]) -> Result<(), Box<dyn Error>> {
let mut file = File::create("toscrape_quotes.csv")?;
let mut writer = csv::Writer::from_writer(&mut file);
for quote in quotes {
writer.write_record(&[quote.text, quote.author, quote.tags.join(", ")])?;
}
writer.flush()?;
Ok(())
}
fn retry_get(client: &Client, url: &str) -> Result<reqwest::Response, Box<dyn Error>> {
let mut retries = 0;
loop {
match client.get(url).send() {
Ok(res) => {
if res.status().is_success() {
return Ok(res);
} else {
retries += 1;
if retries >= MAX_RETRIES {
return Err(format!("GET request to {} failed with status code {:?}", url, res.status()).into());
}
}
}
Err(err) => {
retries += 1;
if retries >= MAX_RETRIES {
return Err(format!("GET request to {} failed with error: {}", url, err).into());
}
}
}
sleep(Duration::from_secs(RETRY_SLEEP_SECONDS));
}
}
Функция main_
Функция mainявляется точкой входа кода Rust и выполняет следующие шаги:
- Создает новый HTTP-клиент, используя
reqwest::Client. - Вызывает
get_quotesфункцию и передает ей клиента, который возвращает векторQuoteструктур. - Вызывает
write_quotes_to_csvфункцию и передает ей векторQuoteструктур, который записывает кавычки в CSV-файл. - Возвращает результат функции
write_quotes_to_csv, который либоOk(())если все удалось, либо ошибку, если что-то пошло не так.
fn main() -> Result<(), Box<dyn Error>> {
let client = Client::new().timeout(Duration::from_secs(30)).build()?;
let quotes = get_quotes(&client)?;
write_quotes_to_csv("es)?;
Ok(())
}
Функция get_quotesпринимает ссылку на reqwest::Clientв качестве аргумента и возвращает вектор Quoteструктур, взятых с веб-сайта.http://quotes.toscrape.com". Вот разбивка того, что мы делаем:
- Инициализировать пустой вектор
Quoteструктур. - Прокрутите страницы, которые нужно очистить, от 1 до
MAX_PAGE. - Для каждой страницы сделайте запрос GET к URL-адресу страницы, используя
retry_getфункцию, и извлеките HTML-код страницы. - Разобрать HTML на
scraper::Htmlфрагмент. - Выберите цитату
text,authorиtagsиз HTML с помощью селекторов CSS. - Создайте новую
Quoteструктуру для каждой цитаты и добавьте ее к вектору цитат. - Вернуть вектор кавычек.
fn get_quotes(client: &Client) -> Result<Vec<Quote>, Box<dyn Error>> {
let mut quotes = Vec::new();
for page in 1..=MAX_PAGE {
let html = retry_get(client, &format!("{}/page/{}/", BASE_URL, page))?.text()?;
let fragment = Html::parse_document(&html);
let quote_selector = Selector::parse("span.text").unwrap();
let author_selector = Selector::parse("span > small.author").unwrap();
let tag_selector = Selector::parse("div.tags > a.tag").unwrap();
for quote in fragment.select("e_selector) {
let quote_text = quote.text().collect::<Vec<_>>()[0].trim().to_owned();
let author = quote
.parent()
.unwrap()
.select(&author_selector)
.next()
.unwrap()
.text()
.collect::<Vec<_>>()[0]
.trim()
.to_owned();
let tags = quote
.parent()
.unwrap()
.select(&tag_selector)
.map(|tag| tag.text().collect::<Vec<_>>()[0].trim().to_owned())
.collect::<Vec<_>>();
quotes.push(Quote {
text: quote_text,
author,
tags,
});
}
}
Ok(quotes)
}
Функция write_quotes_to_csvпринимает ссылку, чтобы нарезать Quoteструктуры и записывать кавычки в .csvфайл. Вот разбивка того, что мы делаем:
- Создайте новый
.csvфайл с именемtoscrape_quotes.csv. - Создайте новый
csv::Writerс помощьюcsvящика. - Запишите новую запись в файл .csv для каждой цитаты в фрагменте цитат с цитатой
text,authorиtagsразделенными запятыми. - Очистите модуль записи, чтобы убедиться, что все данные записаны в файл.
- Возвращает результат операции записи, то есть либо
Ok(())если все удалось, либо ошибку, если что-то пошло не так.
fn write_quotes_to_csv(quotes: &[Quote]) -> Result<(), Box<dyn Error>> {
let mut file = File::create("toscrape_quotes.csv")?;
let mut writer = csv::Writer::from_writer(&mut file);
for quote in quotes {
writer.write_record(&[quote.text, quote.author, quote.tags.join(", ")])?;
}
writer.flush()?;
Ok(())
}
Функция retry_getпринимает ссылку reqwest::Clientи ссылку на строковый URL-адрес и отправляет HTTP-запрос GET к URL-адресу с помощью клиента. Если запрос завершается неудачно, функция повторяет запрос максимальное количество MAX_RETRIESраз с интервалом ожидания в RETRY_SLEEP_SECONDSсекундах между каждой повторной попыткой. Вот разбивка того, что мы делаем:
- Инициализируйте счетчик количества попыток.
- Сделайте запрос GET к URL-адресу с помощью клиента и получите ответ.
- Если ответ успешен (т. е. код состояния ответа находится в диапазоне 2xx), верните ответ.
- Если ответ не удался, увеличьте счетчик повторных попыток.
- Если счетчик повторов меньше
MAX_RETRIES, подождите несколькоRETRY_SLEEP_SECONDSсекунд и повторите запрос GET. - Если счетчик повторных попыток равен
MAX_RETRIES, вернуть ошибку, указывающую, что запрос GET не выполнен.
fn retry_get(client: &Client, url: &str) -> Result<reqwest::Response, Box<dyn Error>> {
let mut retries = 0;
loop {
match client.get(url).send() {
Ok(res) => {
if res.status().is_success() {
return Ok(res);
} else {
retries += 1;
if retries >= MAX_RETRIES {
return Err(format!("GET request to {} failed with status code {:?}", url, res.status()).into());
}
}
}
Err(err) => {
retries += 1;
if retries >= MAX_RETRIES {
return Err(format!("GET request to {} failed with error: {}", url, err).into());
}
}
}
sleep(Duration::from_secs(RETRY_SLEEP_SECONDS));
}
}
Тем не менее, Rust является относительно новым языком по сравнению с более продвинутыми языками программирования веб-скрейпинга, такими как Python. Следовательно, у него может быть меньшее сообщество и меньше доступных библиотек. Синтаксис Rust также может быть более сложным для новичков, особенно для тех, кто знаком с языками программирования высокого уровня, такими как Python с динамической семантикой.
Будьте умны, получайте удовольствие от поиска в Интернете и избегайте корпоративных юристов. Зато юристы будут! Хэштег, что? #Счета

![В любом случае, что такое связанный список? [Часть 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































