جستجوگر پیوند چند تِردی
اجازه دهید از دانش جدید خود برای ایجاد یک جستجوگر لینک multi-thread استفاده کنیم. باید از یک صفحه وب شروع شود و بررسی کنید که لینکهای موجود در صفحه معتبر هستند. باید بهصورت بازگشتی صفحات دیگر را در همان دامنه بررسی کند و این کار را تا زمانی که همه صفحات تأیید نشدهاند ادامه دهد.
برای این کار به یک کلاینت HTTP مانند reqwest
نیاز دارید. شما همچنین به راهی برای یافتن لینکها نیاز دارید، ما می توانیم از reqwest
استفاده کنیم. در نهایت، ما به روشی برای رسیدگی به خطاها نیاز داریم پس درنتیجه از thiserror
استفاده خواهیم کرد.
Create a new Cargo project and reqwest
it as a dependency with:
cargo new link-checker
cd link-checker
cargo add --features blocking,rustls-tls reqwest
cargo add scraper
cargo add thiserror
اگر
cargo add
باerror: no such subcommand
ناموفق بود، لطفاً فایلCargo.toml
را دستی ویرایش کنید و وابستگیهای ذکر شده در زیر را اضافه کنید.
فراخوانیها cargo add
را در فایل Cargo.toml
بهصورت زیر بهروزرسانی میکند:
[package]
name = "link-checker"
version = "0.1.0"
edition = "2021"
publish = false
[dependencies]
reqwest = { version = "0.11.12", features = ["blocking", "rustls-tls"] }
scraper = "0.13.0"
thiserror = "1.0.37"
اکنون می توانید صفحه شروع را دانلود کنید. با یک سایت کوچک مانند https://www.google.org/
امتحان کنید.
فایل src/main.rs
شما باید چیزی شبیه به این باشد:
use reqwest::blocking::Client; use reqwest::Url; use scraper::{Html, Selector}; use thiserror::Error; #[derive(Error, Debug)] enum Error { #[error("request error: {0}")] ReqwestError(#[from] reqwest::Error), #[error("bad http response: {0}")] BadResponse(String), } #[derive(Debug)] struct CrawlCommand { url: Url, extract_links: bool, } fn visit_page(client: &Client, command: &CrawlCommand) -> Result<Vec<Url>, Error> { println!("بررسی {:#}", command.url); let response = client.get(command.url.clone()).send()?; if !response.status().is_success() { return Err(Error::BadResponse(response.status().to_string())); } let mut link_urls = Vec::new(); if !command.extract_links { return Ok(link_urls); } let base_url = response.url().to_owned(); let body_text = response.text()?; let document = Html::parse_document(&body_text); let selector = Selector::parse("a").unwrap(); let href_values = document .select(&selector) .filter_map(|element| element.value().attr("href")); for href in href_values { match base_url.join(href) { Ok(link_url) => { link_urls.push(link_url); } Err(err) => { println!("On {base_url:#}: ignored unparsable {href:?}: {err}"); } } } Ok(link_urls) } fn main() { let client = Client::new(); let start_url = Url::parse("https://www.google.org").unwrap(); let crawl_command = CrawlCommand{ url: start_url, extract_links: true }; match visit_page(&client, &crawl_command) { Ok(links) => println!("Links: {links:#?}"), Err(err) => println!("نمیتواند لینک را باز کند: {err:#}"), } }
این کد را در src/main.rs
اجرا کنید
cargo run
Task
- برای بررسی موازی لینکها از threadها استفاده کنید: URLهایی را که باید بررسی شوند به یک channel ارسال کنید و اجازه دهید چند thread بهصورت موازی URLها را بررسی کنند.
- این را به صورت بازگشتی پیوندها گسترش دهید تا از همه صفحات را در دامنه «www.google.org» استخراج کنید. حد بالا را حدود ۱۰۰ صفحه یا بیشتر قرار دهید تا در نهایت توسط سایت مسدود نشوید.