En este artículo, escribí algunos pequeños programas para mostrarle cómo funciona el análisis de páginas web en Rust.
Para esta tarea, elegí: bibliotecas Tokio, Reqwest y Scraper .
Es una biblioteca para escribir aplicaciones confiables, asincrónicas y delgadas con el lenguaje de programación Rust.
Por qué elijo Tokio:
Lista de proyectos que usan Tokio, basada en el repositorio Github de Tokio :
Un cliente HTTP ergonómico con baterías incluidas para Rust.
Características:
Reqwest usa Tokio para solicitudes asíncronas y tiene un modo de trabajo de bloqueo. En este artículo, utilicé el modo asíncrono.
Scraper proporciona una interfaz para html5ever y cajas de selectores de Servo, para análisis y consultas de nivel de navegador.
use scraper::{Html, Selector}; #[tokio::main]
async fn main () -> Result <(), Box < dyn std::error::Error>> { let resp = reqwest::get( "https://www.wireshark.org/download/" ). await ?; let text = resp.text(). await ?; let document = Html::parse_document(&text); let selector = Selector::parse( r#"table > tbody > tr > td > a"# ).unwrap(); for title in document.select(&selector) { println! ( "{}" , resp.url().to_string()); println! ( "{}" , title .value() .attr( "href" ) .expect( "href not found" ) .to_string() ); } Ok (()) }
Aquí hay una pequeña actualización para este programa. Aquí la página de Whireshark tiene enlaces duplicados. Podemos ignorarlos usando un hashmap.
use scraper::{Html, Selector}; use std::collections::HashSet; #[tokio::main]
async fn main () -> Result <(), Box < dyn std::error::Error>> { let resp = reqwest::get( "https://www.wireshark.org/download/" ). await ?; println! ( "{}" , resp.url().to_string()); let text = resp.text(). await ?; let mut urls:HashSet< String > = HashSet::new(); let document = Html::parse_document(&text); let selector = Selector::parse( r#"table > tbody > tr > td > a"# ).unwrap(); for title in document.select(&selector) { let url = title.value().attr( "href" ).expect( "href not found" ).to_string(); if url != "/" || url != "." || url != ".." { urls.insert(url); } } for url in urls{ println! ( "{}" , url); } Ok (()) }
Para la próxima iteración, quiero mostrarles cómo hacer un analizador menos complejo, pero con más funciones.
Tarea: recopila nuevos fondos de pantalla del sitio web de Wallheaven.
En este sitio, puede encontrar el botón "aleatorio" que le brinda 24 imágenes aleatorias. Para esta tarea, necesitamos analizar esta página. Después de eso, vaya a la URL de la imagen, obtenga una URL de imagen de tamaño completo y descargue la imagen.
use scraper::{Html, Selector}; use std::io::Cursor; use std::process; #[tokio::main]
async fn main () -> Result <(), Box < dyn std::error::Error>> { let resp = match reqwest::get( "https://wallhaven.cc/random" ). await { Ok (x) => x, Err (_) => { println! ( "{}" , "error on /random request" ); process::exit( 0x0100 ); //exit if error expected during request to /random
} }; let text = resp.text(). await ?; let document = Html::parse_document(&text); let selector = Selector::parse( r#"ul > li > figure > a"# ).unwrap(); for elem in document.select(&selector) { let href = elem.value().attr( "href" ).expect( "href not found!" ); download(&href.to_string()). await ?; } Ok (()) } async fn download (url: & String ) -> Result <(), Box < dyn std::error::Error>> { let resp = reqwest::get(url). await ?; let text = resp.text(). await ?; let document = Html::parse_document(&text); let selector = Selector::parse( r#"img"# ).unwrap(); for elem in document.select(&selector) { let picture_url = elem.value().attr( "data-cfsrc" ); match picture_url { Some (x) => { // ignoring another pictures on page like logo and avatar
if x.contains( "avatar" ) || x.contains( "logo" ) { continue ; } // trying to get original name of picture
let file_path = x.split( "/" ).last().expect( "cant find filename" ); match reqwest::get(x). await { Ok (x) => { let mut file = std::fs::File::create(file_path)?; let mut content = Cursor::new(x.bytes(). await ?); std::io::copy(& mut content, & mut file)?; println! ( "Created: {}" , file_path); } Err (_) => { continue ; } }; } None => {} } } Ok (()) }
En conclusión, quiero mostrar y resolver algunas tareas prácticas de análisis sintáctico con fines educativos y refactorizados no tan bien como sea posible. Para la producción, vea mejores ejemplos y desarrolle sus propias tareas.