4 个版本 (2 个破坏性更新)

0.3.1 2023 年 4 月 3 日
0.3.0 2023 年 4 月 1 日
0.2.0 2023 年 2 月 26 日
0.1.0 2022 年 8 月 20 日

#1704 in 网页编程

每月 44 次下载

MIT 许可证

49KB
1K SLoC

Frangipani

本项目目标是创建一个可配置和可扩展的爬虫框架。

特性

  • 连续抓取
  • 并发抓取
  • 遵守 robots.txt

用法

use async_trait::async_trait;
use frangipani::{Response, Spider};
use frangipani::util::join_url;
use scraper::{Html, Selector};

pub struct DexcodeSpider {
}

#[async_trait]
impl Spider for DexcodeSpider {
    fn name(&self) -> String {
        "dexcode-spider".to_owned()
    }
    
    fn start_urls(&self) -> Vec<String> {
        vec![
            "https://dexcode.com/".to_owned(),
        ]
    }
    
    async fn parse(&self, response: Response) -> (u64, Vec<String>) {
        if response.content_type() != "text/html" {
            return (0, vec![]);
        }

        let url = response.get_url().to_owned();
        let text = response.into_string().unwrap();
        
        let mut urls = vec![];
        {
            let document = Html::parse_document(&text);
            let link_selector = Selector::parse("a").unwrap();
            for link in document.select(&link_selector) {
                if let Some(relative_url) = link.value().attr("href") {
                    let join_url = join_url(&url, relative_url);
                    let req_url = reqwest::Url::parse(&join_url).unwrap();
                    if req_url.scheme() != "http" && req_url.scheme() != "https" {
                        continue;
                    }
                    if req_url.domain().unwrap().ends_with("dexcode.com") {
                        // Only push url with `dexcode.com` domain
                        urls.push(req_url.to_string());
                    }
                }
            }

            let title_selector = Selector::parse("title").unwrap();
            let title = match document.select(&title_selector).next() {
                Some(el) => el.inner_html(),
                None => "".to_owned(),
            };
            println!("{},{}", url, title);
        }
        
        (1, urls)
    }
}

#[tokio::main]
async fn main() {
    env_logger::init();

    let spiders: Vec<Box<dyn Spider + Send + Sync>> = vec![
        Box::new(DexcodeSpider {}),
    ];

    let mut engine = frangipani::engine(spiders);
    engine.start().await;
}

对于连续抓取,请参阅项目仓库中的 examples/continuous.rs

依赖

~37–56MB
~1M SLoC