0

我开始使用Druid crate 和Crabler crate 编写程序来制作我可以探索其数据的网络抓取应用程序。在我花了一段时间构建这个程序很久之后,我才意识到合并同步和异步编程是一个坏主意。我现在要做的是在应用程序打开时运行刮板(最好是每小时一次)。

现在刮板直到应用程序关闭后才会运行。我尝试使用 Tokiospawn创建一个在应用程序打开之前启动的单独线程,但这不起作用,因为 Crabler 未来没有“发送”特性。

我试图制作一个最小的功能程序,如下所示。没有按预期运行,title_handler但它表明了我遇到的问题。

是否可以在应用程序打开时允许 WebScraper 运行?如果是这样,怎么做?

编辑:我尝试使用task::spawn_blocking()来运行应用程序,但它抛出了大量错误,包括 druid 没有实现 trait Send

use crabler::*;
use druid::widget::prelude::*;
use druid::widget::{Align, Flex, Label, TextBox};
use druid::{AppLauncher, Data, Lens, WindowDesc, WidgetExt};

const ENTRY_PREFIX: [&str; 1] = ["https://duckduckgo.com/?t=ffab&q=rust&ia=web"];

// Use WebScraper trait to get each item with the ".result__title" class
#[derive(WebScraper)]
#[on_response(response_handler)]
#[on_html(".result__title", title_handler)]

struct Scraper {}

impl Scraper {
    // Print webpage status
    async fn response_handler(&self, response: Response) -> Result<()> {
        println!("Status {}", response.status);
        Ok(())
    }

    async fn title_handler(&self, _: Response, el: Element) -> Result<()> {
        // Get text of element
        let title_data = el.children();
        let title_text = title_data.first().unwrap().text().unwrap();
        println!("Result is {}", title_text);
        Ok(())
    }
}

// Run scraper to get info from https://duckduckgo.com/?t=ffab&q=rust&ia=web
async fn one_scrape() -> Result<()> {
    let scraper = Scraper {};
    scraper.run(Opts::new().with_urls(ENTRY_PREFIX.to_vec()).with_threads(1)).await
}

#[derive(Clone, Data, Lens)]
struct Init {
    tag: String,
}


fn build_ui() -> impl Widget<Init> {
    // Search box
    let l_search = Label::new("Search: ");
    let tb_search = TextBox::new()
        .with_placeholder("Enter tag to search")
        .lens(Init::tag);
    let search = Flex::row()
        .with_child(l_search)
        .with_child(tb_search);

    // Describe layout of UI
    let layout = Flex::column()
        .with_child(search);
    
    Align::centered(layout)
}

#[async_std::main]
async fn main() -> Result<()> {
    // Describe the main window
    let main_window = WindowDesc::new(build_ui())
        .title("Title Tracker")
        .window_size((400.0, 400.0));

    // Create starting app state
    let init_state = Init {
        tag: String::from("#"),
    };

    // Start application
    AppLauncher::with_window(main_window)
        .launch(init_state)
        .expect("Failed to launch application");

    one_scrape().await
}
4

0 回答 0