Извлечение ссылок
Извлечение всех ссылок из веб-страницы HTML
Используется reqwest::get
для выполнения HTTP GET-запроса и затем используется метод Document::from_read
для разбора ответа как HTML документа. find
с условием, что 'Name
должен быть "a"' извлекает все ссылки. Вызов filter_map
на результате Selection
извлекает все URL адреса из ссылок с атрибутом "href", атрибуты можно получить с помощью метода attr
(атрибут).
#[macro_use] extern crate error_chain; extern crate reqwest; extern crate select; use select::document::Document; use select::predicate::Name; error_chain! { foreign_links { ReqError(reqwest::Error); IoError(std::io::Error); } } fn main() -> Result<()> { let res = reqwest::get("https://www.rust-lang.org/en-US/")?; Document::from_read(res)? .find(Name("a")) .filter_map(|n| n.attr("href")) .for_each(|x| println!("{}", x)); Ok(()) }
Проверка веб-страницы на наличие неработающих ссылок
В примере вызывается функция get_base_url
чтобы получить базовый URL адрес. Если в документе найден нужный тэг, можно затем получить атрибут href через attr
из базового тэга. Position::BeforePath
для изначального URL адреса работает как адрес по умолчанию.
Затем производится итерация по ссылкам в документе и разбор с помощью url::ParseOptions
и Url::parse
). Далее выполняются запросы по полученным ссылкам с помощью функций из крейта reqwest и у соответствующих ответов проверяются его StatusCode
.
#[macro_use] extern crate error_chain; extern crate reqwest; extern crate select; extern crate url; use std::collections::HashSet; use url::{Url, Position}; use reqwest::StatusCode; use select::document::Document; use select::predicate::Name; error_chain! { foreign_links { ReqError(reqwest::Error); IoError(std::io::Error); UrlParseError(url::ParseError); } } fn get_base_url(url: &Url, doc: &Document) -> Result<Url> { let base_tag_href = doc.find(Name("base")).filter_map(|n| n.attr("href")).nth(0); let base_url = base_tag_href.map_or_else( || Url::parse(&url[..Position::BeforePath]), Url::parse, )?; Ok(base_url) } fn check_link(url: &Url) -> Result<bool> { let res = reqwest::get(url.as_ref())?; Ok(res.status() != StatusCode::NOT_FOUND) } fn main() -> Result<()> { let url = Url::parse("https://www.rust-lang.org/en-US/")?; let res = reqwest::get(url.as_ref())?; let document = Document::from_read(res)?; let base_url = get_base_url(&url, &document)?; let base_parser = Url::options().base_url(Some(&base_url)); let links: HashSet<Url> = document .find(Name("a")) .filter_map(|n| n.attr("href")) .filter_map(|link| base_parser.parse(link).ok()) .collect(); links .iter() .filter(|link| check_link(link).ok() == Some(false)) .for_each(|x| println!("{} is broken.", x)); Ok(()) }
Извлечение всех уникальных ссылок из разметки MediaWiki
Данный пример вытягивает исходный код MediaWiki-страницы используя reqwest::get
и затем ищет все внутренние и внешние ссылки с помощью регулярных выражений и метода Regex::captures_iter
. Используется Cow
, чтобы избежать излишних выделений объектов String
на куче.
Синтаксис ссылок MediaWiki описан здесь.
#[macro_use] extern crate error_chain; #[macro_use] extern crate lazy_static; extern crate reqwest; extern crate regex; use std::io::Read; use std::collections::HashSet; use std::borrow::Cow; use regex::Regex; error_chain! { foreign_links { Io(std::io::Error); Reqwest(reqwest::Error); Regex(regex::Error); } } fn extract_links(content: &str) -> Result<HashSet<Cow<str>>> { lazy_static! { static ref WIKI_REGEX: Regex = Regex::new(r"(?x) \[\[(?P<internal>[^\[\]|]*)[^\[\]]*\]\] # internal links | (url=|URL\||\[)(?P<external>http.*?)[ \|}] # external links ").unwrap(); } let links: HashSet<_> = WIKI_REGEX .captures_iter(content) .map(|c| match (c.name("internal"), c.name("external")) { (Some(val), None) => Cow::from(val.as_str().to_lowercase()), (None, Some(val)) => Cow::from(val.as_str()), _ => unreachable!(), }) .collect(); Ok(links) } fn main() -> Result<()> { let mut content = String::new(); reqwest::get( "https://en.wikipedia.org/w/index.php?title=Rust_(programming_language)&action=raw", )? .read_to_string(&mut content)?; println!("{:#?}", extract_links(&content)?); Ok(()) }