Usando Rust para Web Scraping
Web Scraping es una técnica de extracción de información de sitios web. Es un proceso automatizado de obtener grandes cantidades de datos de sitios web, ahorrando tiempo y esfuerzo, y haciendo que la información esté disponible para varios propósitos.
En esta publicación, demostraré cómo puede usar Rust para extraer citas de un sitio web.
Ventajas de usar Rust para Web Scraping
- Rendimiento : Rust es un lenguaje compilado de tipo estático que proporciona un alto rendimiento, lo que lo convierte en una opción ideal para el web scraping.
- Concurrencia : Rust proporciona soporte de concurrencia incorporado, lo que facilita el manejo de múltiples solicitudes simultáneamente, mejorando la eficiencia del web scraping.
- Seguridad de la memoria : Rust proporciona sólidas garantías de seguridad de la memoria, lo que ayuda a prevenir errores comunes relacionados con la memoria, como excepciones de puntero nulo y desbordamientos de búfer, lo que lo hace más seguro para el web scraping.
- Fácil de aprender : Rust tiene una sintaxis relativamente simple, lo que facilita el aprendizaje de los desarrolladores, en comparación con otros lenguajes de programación.
- Curva de aprendizaje pronunciada : si bien la sintaxis de Rust es relativamente simple, el lenguaje puede ser difícil de aprender, especialmente para los desarrolladores que son nuevos en los lenguajes compilados de tipo estático.
- Comunidad limitada : si bien Rust tiene una comunidad en crecimiento, todavía no se usa tanto como otros lenguajes de programación, lo que significa que encontrar recursos y soporte puede ser difícil.
- Sin biblioteca de web scraping incorporada : Rust no tiene una biblioteca integrada para web scraping, lo que significa que los desarrolladores tienen que usar bibliotecas de terceros, lo que puede ser menos conveniente.
Ahora, instalaremos Rust, verificaremos la versión de Cargoe instalaremos tres bibliotecas de web scraping, reqwest, scrapery selecta través de la interfaz de línea de comandos.
Instalar óxido
Para instalar Rust, puede usar la herramienta Rustup, que es la forma recomendada de instalar Rust. Puedes ejecutar el siguiente comando en tu terminal:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Instalar carga
Cargo es el administrador de paquetes de Rust y se instala automáticamente cuando instala Rust. Puede verificar si Cargo está instalado ejecutando el siguiente comando:
cargo --version
Ejecute el siguiente comando en su terminal:
cargo new toscrape_quotes
Para instalar las bibliotecas de raspado web de Rust reqwest, scrapery select, puede agregar las siguientes dependencias a su Cargo.tomlarchivo:
# 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 .
Hagamos un poco de Web Scraping. ¿Debemos?
Toscrape.com es una caja de arena de raspado web para aquellos que quieren incursionar en tal esfuerzo en ingeniería de software.
Sin atraer la atención no deseada de abogados corporativos de plataformas u organizaciones empresariales, puede usarlo como su patio de recreo. ¡Sí, no quieres ver a esa gente! Algunos usan trajes combinados con Air Jordan 1 Chicago .
Código de raspado web de óxido
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));
}
}
la mainfunción
La mainfunción es el punto de entrada del código Rust y realiza los siguientes pasos:
- Crea un nuevo cliente HTTP usando
reqwest::Client. - Llama a la
get_quotesfunción y le pasa el cliente, que devuelve un vector deQuoteestructuras. - Llama a la función y le
write_quotes_to_csvpasa el vector de estructuras, que escribe las comillas en un archivo .csv.Quote - Devuelve el resultado de la
write_quotes_to_csvfunción, que esOk(())si todo salió bien o un error si algo salió mal.
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(())
}
La get_quotesfunción toma una referencia a reqwest::Clientcomo argumento y devuelve un vector de Quoteestructuras que se extraen del sitio web "http://quotes.toscrape.com". Aquí hay un desglose de lo que estamos haciendo:
- Inicialice un vector vacío de
Quoteestructuras. - Recorra las páginas que desea raspar, de 1 a
MAX_PAGE. - Para cada página, realice una solicitud GET a la URL de la página usando la
retry_getfunción y recupera el HTML de la página. - Analizar el HTML en un
scraper::Htmlfragmento. - Seleccione la cita
text,authorytagsdel HTML usando los selectores de CSS. - Cree una nueva
Quoteestructura para cada cotización y agréguela al vector de cotizaciones. - Devuelve el vector de comillas.
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)
}
La write_quotes_to_csvfunción toma una referencia para dividir las Quoteestructuras y escribir las comillas en un .csvarchivo. Aquí hay un desglose de lo que estamos haciendo:
- Cree un nuevo
.csvarchivo con el nombretoscrape_quotes.csv. - Cree uno nuevo
csv::Writerusando lacsvcaja. - Escriba un nuevo registro en el archivo .csv para cada cita en la porción de comillas, con la cita
text,authorytagsseparada por comas. - Vacíe el escritor para asegurarse de que todos los datos se escriben en el archivo.
- Devuelve el resultado de la operación de escritura, que es
Ok(())si todo tuvo éxito o un error si algo salió mal.
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(())
}
La retry_getfunción toma una referencia reqwest::Clienty una referencia a la URL de la cadena y realiza una solicitud HTTP GET a la URL utilizando el cliente. Si la solicitud falla, la función vuelve a intentar la solicitud un máximo de MAX_RETRIESveces con un tiempo de inactividad de RETRY_SLEEP_SECONDSsegundos entre cada reintento. Aquí hay un desglose de lo que estamos haciendo:
- Inicialice un contador para el número de reintentos.
- Realice una solicitud GET a la URL utilizando el cliente y recupere la respuesta.
- Si la respuesta es exitosa (es decir, el código de estado de la respuesta está en el rango 2xx), devuelva la respuesta.
- Si la respuesta no es exitosa, incremente el contador de reintentos.
- Si el contador de reintentos es inferior a
MAX_RETRIES, espere unosRETRY_SLEEP_SECONDSsegundos y vuelva a intentar la solicitud GET. - Si el contador de reintentos es igual a
MAX_RETRIES, devuelve un error que indica que la solicitud GET falló.
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));
}
}
Sin embargo, Rust es un lenguaje relativamente nuevo en comparación con lenguajes de programación de web scraping más avanzados como Python. Por lo tanto, puede tener una comunidad más pequeña y menos bibliotecas disponibles. La sintaxis de Rust también puede ser más difícil para los principiantes, especialmente para aquellos que están familiarizados con lenguajes de programación de alto nivel como Python con semántica dinámica.
Sea inteligente, diviértase raspando la web y evite los abogados corporativos. ¡Pero habrá abogados! Etiqueta, ¿qué? #Facturables

![¿Qué es una lista vinculada, de todos modos? [Parte 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































