Usare Rust per il Web Scraping
Il web scraping è una tecnica per estrarre informazioni dai siti web. È un processo automatizzato di recupero di grandi quantità di dati da siti Web, risparmiando tempo e fatica e rendendo le informazioni disponibili per vari scopi.
In questo post, dimostrerò come utilizzare Rust per estrarre citazioni da un sito web.
Vantaggi dell'utilizzo di Rust per il web scraping
- Prestazioni : Rust è un linguaggio compilato con tipizzazione statica che offre prestazioni elevate, rendendolo la scelta ideale per il web scraping.
- Concorrenza : Rust fornisce un supporto integrato per la concorrenza, che semplifica la gestione di più richieste contemporaneamente, migliorando l'efficienza del web scraping.
- Sicurezza della memoria : Rust offre solide garanzie di sicurezza della memoria, che aiutano a prevenire bug comuni relativi alla memoria, come eccezioni di puntatori null e overflow del buffer, rendendolo più sicuro per il web scraping.
- Facile da imparare : Rust ha una sintassi relativamente semplice, che rende più facile l'apprendimento per gli sviluppatori, rispetto ad altri linguaggi di programmazione.
- Curva di apprendimento ripida : sebbene la sintassi di Rust sia relativamente semplice, il linguaggio può essere difficile da imparare, specialmente per gli sviluppatori che sono nuovi ai linguaggi compilati con tipizzazione statica.
- Comunità limitata : sebbene Rust abbia una comunità in crescita, non è ancora ampiamente utilizzato come altri linguaggi di programmazione, il che significa che trovare risorse e supporto può essere difficile.
- Nessuna libreria di web scraping integrata : Rust non ha una libreria integrata per il web scraping, il che significa che gli sviluppatori devono utilizzare librerie di terze parti, il che può essere meno conveniente.
Ora installeremo , Rustverificheremo la versione di Cargoe installeremo tre librerie di web scraping, reqwest, scrapere selecttramite l'interfaccia della riga di comando.
Installa ruggine
Per installare Rust, puoi utilizzare lo strumento Rustup, che è il metodo consigliato per installare Rust. Puoi eseguire il seguente comando nel tuo terminale:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Installa il carico
Cargo è il gestore di pacchetti per Rust e viene installato automaticamente quando installi Rust. Puoi verificare se Cargo è installato eseguendo il seguente comando:
cargo --version
Esegui il seguente comando nel tuo terminale:
cargo new toscrape_quotes
Per installare le librerie di web scraping Rust reqwest, scraper, e select, puoi aggiungere le seguenti dipendenze al tuo Cargo.tomlfile:
# 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 .
Facciamo un po' di web scraping. Lo facciamo?
Toscrape.com è una sandbox di web-scraping per coloro che vogliono fare un'incursione in un simile sforzo nell'ingegneria del software.
Senza attirare attenzioni indesiderate da parte di avvocati aziendali di piattaforme o organizzazioni aziendali, puoi usarlo come parco giochi. Sì, non vuoi vedere quelle persone! Alcuni indossano completi abbinati ad Air Jordan 1 Chicago .
Codice Rust Web Scraping
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 mainfunzione
La mainfunzione è il punto di ingresso del codice Rust ed esegue i seguenti passaggi:
- Crea un nuovo client HTTP utilizzando
reqwest::Client. - Chiama la
get_quotesfunzione e le passa il client, che restituisce un vettore diQuotestruct. - Chiama la
write_quotes_to_csvfunzione eQuotele passa il vettore di struct, che scrive le virgolette in un file .csv. - Restituisce il risultato della
write_quotes_to_csvfunzione, ovveroOk(())se tutto è andato a buon fine o un errore se qualcosa è andato storto.
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_quotesfunzione prende un riferimento a reqwest::Clientcome argomento e restituisce un vettore di Quotestruct che vengono prelevati dal sito web "http://quotes.toscrape.com". Ecco una ripartizione di ciò che stiamo facendo:
- Inizializza un vettore vuoto di
Quotestruct. - Scorri le pagine da raschiare, da 1 a
MAX_PAGE. - Per ogni pagina, effettua una richiesta GET all'URL della pagina utilizzando la
retry_getfunzione e recupera l'HTML della pagina. - Analizza l'HTML in un
scraper::Htmlframmento. - Seleziona la citazione
text,authoretagsdall'HTML utilizzando i selettori CSS. - Crea una nuova
Quotestruttura per ogni citazione e aggiungila al vettore delle virgolette. - Restituisce il vettore delle virgolette.
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_csvfunzione accetta un riferimento per suddividere le Quotestrutture e scrivere le virgolette in un .csvfile. Ecco una ripartizione di ciò che stiamo facendo:
- Crea un nuovo
.csvfile con il nometoscrape_quotes.csv. - Creane uno nuovo
csv::Writerusando lacsvcassa. - Scrivi un nuovo record nel file .csv per ogni citazione nella sezione delle virgolette, con le virgolette
text,authoretagsseparate da virgole. - Svuota il writer per garantire che tutti i dati vengano scritti nel file.
- Restituisce il risultato dell'operazione di scrittura, ovvero
Ok(())se tutto è andato a buon fine o un errore se qualcosa è andato storto.
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_getfunzione accetta un riferimento reqwest::Cliente un riferimento all'URL della stringa e invia una richiesta HTTP GET all'URL utilizzando il client. Se la richiesta ha esito negativo, la funzione riprova la richiesta un massimo di MAX_RETRIESvolte con un tempo di sospensione di RETRY_SLEEP_SECONDSsecondi tra ogni tentativo. Ecco una ripartizione di ciò che stiamo facendo:
- Inizializza un contatore per il numero di tentativi.
- Effettua una richiesta GET all'URL utilizzando il client e recupera la risposta.
- Se la risposta ha esito positivo (ovvero, il codice di stato della risposta è nell'intervallo 2xx), restituire la risposta.
- Se la risposta non va a buon fine, incrementa il contatore dei tentativi.
- Se il contatore dei tentativi è inferiore a
MAX_RETRIES, attendere alcuniRETRY_SLEEP_SECONDSsecondi e riprovare la richiesta GET. - Se il contatore dei tentativi è uguale a
MAX_RETRIES, restituisce un errore che indica che la richiesta GET non è riuscita.
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));
}
}
Tuttavia, Rust è un linguaggio relativamente nuovo rispetto ai linguaggi di programmazione di web scraping più avanzati come Python. Pertanto, potrebbe avere una comunità più piccola e meno biblioteche disponibili. La sintassi di Rust può anche essere più difficile per i principianti, specialmente quelli che hanno familiarità con linguaggi di programmazione di alto livello come Python con semantica dinamica.
Sii intelligente, divertiti a raschiare il web ed evita gli avvocati aziendali. Ci saranno avvocati, però! Hashtag, cosa? #Fatturabili

![Che cos'è un elenco collegato, comunque? [Parte 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































