Просто спарсь что угодно с помощью языка Rust (ну… или просто скачай файл)

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Известно, что Rust — типобезопасный язык программирования, код которого проверяется пакетным менеджером cargo ещё до сборки. С одной стороны это хорошо: меньше вероятности внезапного сбоя в самый неподходящий момент. С другой стороны — код, выполняющий одну функцию, в итоге может стать очень сложным и иногда нечитаемым.

В пример привожу функцию, которая парсит названия валют с сайта floatrates и выводит их (пожалуйста, напишите в комментариях, за сколько минут вы поняли эту строку):

// main.rs
use reqwest::blocking::get
use scraper::{Html, Selector}

fn main {
    let url = "http://www.floatrates.com/json-feeds.html";
    let response = get(url).except("Ссылка не загружается.");
    let body = response.text().unwarp();
    let document = Html::parse_document(&body);

    let selector = Selector::parse("div.bk-json-feeds>div.body>ul>li>a").unwarp()
        .iter()
        .map(|element| element.inner_html())
        .collect()
        .foreach(|title| println!("{title}"));
}

В этой статье я хочу рассказать о своей новой библиотеке, значительно упрощающей парсинг на Rust. Приятного чтения!

Дисклеймер

Пожалуйста, не «бейте» меня за некоторые ошибки в терминах, в // и ///</p>" data-abbr="комментариях">комментариях или в синтаксисе кода: я программирую на Rust всего 2 месяца.

Однако опыт в программировании у меня есть (год в python), поэтому прекрасно понимаю, о чём здесь пишу.

Буду очень признателен, если вы напишите в комментариях, что нужно исправить в крэйте)

Благодарю reloginn за помощь в разработке версии 1.0.0

Инициализация структуры Scraper

// scr::scraping
use reqwest::blocking;
use scraper::{ElementRef, Html, Selector};

/// Простой парсер
/// // ...
pub struct Scraper {
    document: Html,
}

Вместо того, чтобы отдельно отправлять запрос, из его результата получать код сайта и инициализировать объект scraper::Html, можно просто вызвать команду let scraper = scr::Scraper::new("scrapeme.live/shop/") (да, «html://» вводить не надо). Структура сохраняет в себе scraper::Html для дальнейшего парсинга. Вот, что происходит «под капотом» инициализатора:

// scr::scraping
// ...
impl Scraper {
    /// создание нового экземпляра парсера,
    /// <i>используя код сайта **(без https://)**</i>
    pub fn new(url: &str) -> Scraper {
        let response = blocking::get(format!("https://{}", url))
            .expect("Сайт не загружается")
            .text()
            .expect("Код сайта не возвращается");

        Scraper {
            document: Html::parse_document(&response),
        }
    }
    // ...
}

Также есть возможность инициализировать структру, используя фрагмент HTML страницы:

// scr::scraping
// ...
impl Scraper {
    // ...
    /// создание нового экземпляра парсера,
    /// <i>используя **фрагмент** кода сайта</i>
    pub fn from_fragment(fragment: &str) -> Scraper {
        Scraper {
            document: Html::parse_fragment(fragment),
        }
    }
    // ...
}

Получение элементов

Под командой scraper.get_els("путь#к>элементам"); скрываются выбор элементов по специальному пути c применением структуры scraper::Selector и преобразование полученного результата в Vec<scraper::ElementRef>.

// scr::scraping
// ...
impl Scraper {
    // ...
    /// получение элементов
    pub fn get_els(&self, sel: &str) -> Vec<ElementRef> {
        self.document
            .select(&Selector::parse(sel).expect("Не получается парсить"))
            .collect()
    }

    /// получение элемента
    pub fn get_el(&self, sel: &str) -> ElementRef {
        *self.get_els(sel).get(0).expect("Элемент не возвращается")
    }
    // ...
}

Получение текста (inner_html) и атрибута элемента (-ов)

Можно получить текст или атрибут как одного, так и нескольких элементов, полученных с помощью scraper.get_els("path#to>els");

// scr::scraping
// ...
impl Scraper {
    // ...
    /// получение текста из элемента
    /// ...
    pub fn get_text_once(&self, sel: &str) -> String {
        self.get_el(sel).inner_html()
    }

    /// получение текста из всех элементов
    /// ...
    pub fn get_all_text(&self, sel: &str) -> Vec<String> {
        self.get_els(sel)
            .iter()
            .map(|element| element.inner_html())
            .collect()
    }

    /// получение атрибута элемента
    /// ...
    pub fn get_attr_once(&self, sel: &str, attr: &str) -> &str {
        self.get_el(sel).value().attr(attr).expect("Can not do")
    }

    /// получение атрибута всех элементов
    /// ...
    pub fn get_all_attr(&self, sel: &str, attr: &str) -> Vec<&str> {
        self.get_els(sel)
            .iter()
            .map(|element| element.value().attr(attr).expect("Не получается"))
            .collect()
    }
}

Загрузка файлов (структура FileLoader)

Это — простой загрузчик файлов. Достаточно просто ввести <code>let file_loader = scr::FileLoader::new("path/to/file")</code></p>" data-abbr="одну команду">одну команду. Исходный код структуры: *тык*

Известная проблема

К сожалению, пока нельзя вернуть экземпляр структуры scr::FileLoader (ошибка [E0515]).

Планы на версию 2.0.0

Пока что scr работает только синхронно, отчего крэйт моментами достаточно медленный. Поэтому через некоторое время я внедрю async (скорее всего отдельной фичей или модулем).

На этом пока всё. Очень надеюсь, что я заинтересовал вас. По желанию вы можете внести изменения в библиотеку, создав форк репозитория, совершив некоторые изменения и отправив их мне через pull request.

Источник: https://habr.com/ru/articles/755728/


Интересные статьи

Интересные статьи

В одном недавнем подкасте о том, кто сейчас главный в Rust, вновь всплыл вопрос о том, кому быть BDFL (великодушным пожизненным диктатором), и Джереми Соллер сказал (это был чемпионский заход на ...
(Примечание переводчика: не нашёл публикации (-ий) по данной теме на Хабре.)Блоуинг Рок, Северная Каролина, 21 декабря 2018 года — организация Great Internet Mersenne Pri...
Мы продолжаем исследовать интересные инструменты, которые помогают прокачивать английский язык. Сегодня это симуляторы свиданий.Их сюжеты основываются на отношениях между...
Вновь обращаемся к экспертизе, собранной в нашем «Мире Hi-Fi». Ранее мы посмотрели, где производят аудиотехнику, рассказали о теории и практике DIY-акустики и настройке д...
Речь пойдёт о Marka Email Generator. Это новый плагин для Фигмы — инструмента, в котором мы работаем с дизайнами и прототипами писем.До 2019 года мы знали два с...