首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何同时抓取未知目的的分页网页?

如何同时抓取未知目的的分页网页?
EN

Stack Overflow用户
提问于 2021-09-24 23:20:30
回答 1查看 177关注 0票数 1

我正在尝试使用tokio异步运行时在Rust中编写一个web爬虫。我希望异步地获取/处理多个页面,但我也希望爬虫在到达末尾时停止(换句话说,如果没有什么可以抓取的东西)。到目前为止,我已经使用从作为Future提供的异步函数获得集体结果,但这显然需要程序事先知道要爬行的总页面。例如:

代码语言:javascript
运行
复制
async fn fetch(_url: String) -> Result<String, ()> {
    tokio::time::sleep(std::time::Duration::from_millis(100)).await;

    Ok(String::from("foo"))
}

#[tokio::main]
async fn main() {
    let search_url = "https://example.com/?page={page_num}";

    let futures = (1..=3)
        .map(|page_num| search_url.replace("{page_num}", &page_num.to_string()))
        .map(|url| fetch(url));

    let _ = futures::future::try_join_all(futures).await.unwrap();
}

铁锈游乐场

在这个简单的例子中,在实际获取页面之前,我必须知道要通过的总页面(1..=3)。我想要的是,不提供任何范围和条件,以停止整个过程。(例如,如果HTML结果包含“未找到”)

我查看了在……上面,但我不确定它是否可以用于此任务。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-09-25 01:00:11

下面大概是如何使用Stream.buffered()来完成这一任务

代码语言:javascript
运行
复制
use futures::{future, stream, StreamExt};

#[derive(Debug)]
struct Error;

async fn fetch_page(page: i32) -> Result<String, Error> {
    println!("fetching page: {}", page);

    // simulate loading pages
    tokio::time::sleep(std::time::Duration::from_millis(100)).await;
    if page < 5 {
        // successfully got page
        Ok(String::from("foo"))
    } else {
        // page doesn't exist
        Err(Error)
    }
}

#[tokio::main]
async fn main() {
    let pages: Vec<String> = stream::iter(1..)
        .map(fetch_page)
        .buffered(10)
        .take_while(|page| future::ready(page.is_ok()))
        .map(|page| page.unwrap())
        .collect()
        .await;

    println!("pages: {:?}", pages);
}

我将详细介绍main()中的步骤:

运行上述代码将输出以下内容,显示每次尝试10次,但只返回到第一次失败:

代码语言:javascript
运行
复制
fetching page: 1
fetching page: 2
fetching page: 3
fetching page: 4
fetching page: 5
fetching page: 6
fetching page: 7
fetching page: 8
fetching page: 9
fetching page: 10
pages: ["foo", "foo", "foo", "foo"]

这掩盖了一些好的东西,如处理不丢失的页面错误或重试,但我希望这能给你一个良好的基础。在这些情况下,您可以使用TryStreamExt上的方法,它专门处理Result的流。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69321918

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档