use pagesift_api::ApiError;
use pagesift_api::types::{ScrapeOptions, SimilarData, SimilarItem};
use pagesift_html::{Html, Selector};
use super::Scraper;
use super::cpu::cpu_task;
impl Scraper {
pub async fn find_similar(
&self,
url: &str,
selector: &str,
opts: &ScrapeOptions,
) -> Result<SimilarData, ApiError> {
Selector::parse(selector)
.map_err(|e| ApiError::invalid(format!("selector {selector:?}: {e}")))?;
let doc = self.scrape(url, opts).await?;
let html = doc.raw_html.unwrap_or_default();
let selector = selector.to_string();
cpu_task(move || similar_in(&html, &selector)).await?
}
}
fn similar_in(html: &str, selector: &str) -> Result<SimilarData, ApiError> {
let doc = Html::parse(html);
let sel = Selector::parse(selector)
.map_err(|e| ApiError::invalid(format!("selector {selector:?}: {e}")))?;
let example = doc.select(&sel).next().ok_or_else(|| {
ApiError::invalid(format!("selector {selector:?} matches nothing on the page"))
})?;
let Some(found) = pagesift_extract::locate::find_similar(example, doc.root()) else {
return Ok(SimilarData::default());
};
Ok(SimilarData {
selector: found.selector,
depth: Some(found.depth),
items: found
.items
.iter()
.map(|n| SimilarItem {
text: n.text().split_whitespace().collect::<Vec<_>>().join(" "),
html: n.html(),
})
.collect(),
})
}