当前位置: 首页 > news >正文

Rust中的异步编程:构建简单的网页爬虫

一、什么是Rust中的Futures和Async?

在Rust中,异步编程基于future(未来)的概念。一个future表示一个当前可能不可用,但将来某个时候可以获得的值。Rust中的Future特征定义了这一概念,任何实现了该特征的类型都表示一个future。

Rust中的异步编程关键元素包括:

  • asyncasync关键字标记函数或代码块,可以被中断并稍后恢复。当你标记一个函数为async时,它将返回一个Future,而不是直接返回结果。

  • awaitawait关键字用于在async函数中暂停函数的执行,直到待处理的future完成。

1.1.示例:并发地获取网页

让我们创建一个命令行程序,它并发地获取两个网页,提取它们的<title>元素,并打印第一个完成的网页的标题。我们将使用trpl crate,它提供了一个简化Rust异步编程的抽象,封装了像futurestokio这样的常见异步库。

1.2.设置项目

首先,我们需要设置一个新的Rust项目,并将trpl crate作为依赖项。

$ cargo new hello-async
$ cd hello-async
$ cargo add trpl

1.3.第一步:定义page_title函数

为了从网页中获取<title>元素,我们定义一个异步函数page_title。该函数将使用trpl::get方法发送HTTP GET请求到指定的URL并获取网页内容。然后,我们通过CSS选择器提取<title>元素。

这是page_title函数的实现:

use trpl::Html;

/// 异步函数,获取指定URL页面的<title>元素
async fn page_title(url: &str) -> Option<String> {
    // 使用trpl库的get方法获取网页内容,text()方法返回网页的文本内容
    let response_text = trpl::get(url).await.text().await;
    
    // 解析HTML并查找<title>标签,返回标题内容
    Html::parse(&response_text)
        .select_first("title")  // 使用CSS选择器查找第一个<title>元素
        .map(|title| title.inner_html())  // 如果找到了<title>,返回其内部HTML内容
}
1.3.1.解释:
  • 我们将函数标记为async,因为我们使用了异步操作,如获取URL (get(url)) 和读取响应体 (text()),这些都是异步操作。
  • get(url)text()都是异步操作,所以我们使用await等待它们完成。
  • 获取到响应后,我们解析HTML并使用select_first("title")方法查找第一个<title>元素。
  • 最后,我们返回<title>元素的内部HTML内容,即页面的标题,返回类型是Option<String>

1.4.第二步:在main函数中调用page_title

接下来,我们需要在main函数中调用page_title函数。然而,Rust不允许将main函数标记为异步函数,因此我们必须使用一个运行时来执行异步代码。我们可以使用trpl::run函数,它初始化异步运行时并运行page_title函数返回的future。

这是更新后的main函数:

fn main() {
    // 从命令行参数中获取两个URL
    let url1 = std::env::args().nth(1).expect("Please provide the first URL");
    let url2 = std::env::args().nth(2).expect("Please provide the second URL");

    // 使用trpl::run运行一个异步代码块
    trpl::run(async {
        // 创建两个异步任务,分别获取两个URL的<title>元素
        let title_fut_1 = page_title(&url1);
        let title_fut_2 = page_title(&url2);

        // 使用race函数并发地执行两个任务,返回第一个完成的结果
        let result = trpl::race(title_fut_1, title_fut_2).await;

        // 根据race函数的结果打印第一个完成的页面标题
        match result {
            trpl::Either::Left(Some(title)) => println!("The title for {} is: {}", url1, title),
            trpl::Either::Right(Some(title)) => println!("The title for {} is: {}", url2, title),
            _ => println!("Could not fetch title for one or both URLs."),
        }
    });
}

1.5.第三步:竞速两个URL

在这个示例中,我们从命令行传入两个URL,分别获取它们的标题,并返回第一个完成的网页。我们使用trpl::race函数,它返回一个值,指示哪个future先完成。

1.5.1解释:
  • 我们并发地调用page_title函数,分别创建两个future:title_fut_1title_fut_2
  • 使用trpl::race等待哪个future先完成。它返回一个值,表示哪个future完成得更早,我们可以根据这个结果处理。
  • 使用match语句打印第一个完成的页面的标题。如果某个页面没有<title>标签,我们也会处理这种情况。

1.6.运行程序

要运行该程序,您需要提供两个URL作为命令行参数。下面是运行爬虫的示例:

$ cargo run -- https://www.rust-lang.org https://www.example.com

输出将显示第一个完成加载的页面的标题:

The title for https://www.rust-lang.org is: Rust Programming Language

1.7.理解Rust中的Async和Futures

在这个示例中,async关键字将函数转换为返回Future的函数,Future代表一个将在未来某个时刻可用的值。这是Rust中异步编程的基本概念。

  • 懒惰的Futures:在Rust中,futures是懒惰的,意味着它们不会在创建时立即执行,而是直到使用await显式等待它们时才会执行。这使得Rust能够优化异步任务并避免不必要的计算。

  • 状态机和执行器:每个async函数都被Rust编译器转换为一个状态机。这些状态机允许程序在await点暂停执行,并在未来某个时刻恢复。异步任务的执行由执行器管理,例如trpl::run函数所提供的执行器。

  • 并发性:通过让两个URL并发执行,我们利用了异步编程的优势,使程序比顺序执行更高效。

二、结论

我们成功地构建了一个简单的异步网页爬虫,能够并发地获取两个网页,并打印第一个完成的网页的标题。在这个过程中,我们学习了Rust中的异步编程的基本概念,包括futures、async/await和并发性。

通过使用trpl crate并理解Rust的异步系统工作原理,你现在可以创建更复杂的异步应用程序,充分利用Rust的并发模型。祝编程愉快!

相关文章:

  • 多通道数据采集和信号生成的模块化仪器如何重构飞机电子可靠性测试体系?
  • 数字化赋能:制造业如何突破低效生产的瓶颈?
  • 光流法处理水流:原理与应用
  • 本地部署DeepSeek全攻略:Ollama+Chatbox保姆级教程
  • 如何使用Python编程实现捕获笔记本电脑麦克风的音频并通过蓝牙耳机实时传输
  • BIO、NIO、AIO解析
  • 【AI学习从零至壹】Numpy基础知识
  • 鸿蒙 ArkUI 实现敲木鱼小游戏
  • 2025年跟上AI新时代:带AI人工智能的蜜罐系统T-Pot
  • 介绍下pdf打印工具类 JasperPrint
  • 使用Apifox动态生成请求参数
  • 源网荷储一体化 EMS3.0:助力企业微电网能效提升
  • JDBC 基础
  • c++中如何打印未知类型对象的类型
  • 学习大模型开发要学什么
  • ssh和rdp踩坑
  • 激活函数表示和应用
  • cFosSpeed 低延迟网络加速器 | 游戏/VoIP 专属优化
  • 制造业数字化实践案例丨国内某大型物联网企业数字化项目管理系统,赋能品牌和生态战略落地
  • 51c自动驾驶~合集52
  • 印对巴军事打击后,巴外交部召见印度驻巴临时代办
  • 习近平《在庆祝中华全国总工会成立100周年暨全国劳动模范和先进工作者表彰大会上的讲话》单行本出版
  • 中演协:五一假期全国营业性演出票房收入同比增长3.6%
  • 深圳一购房者交首付后迟迟无法签合同,澎湃介入后开发商承诺退款
  • “模”范生上海,如何再进阶?
  • 在海拔3980米驻守:“全国先进工作者”刘鹏与洛戈梁子警务站的9年