返回博客

Rust 语言教程:使用 Rust 编程进行网络抓取

Maryia Stsiopkina

2022-11-30
2 min read

Rust 编程语言作为一种能够提供与 C/C++ 高性能相媲美的编程语言,受到越来越多用户关注,尤其是在网络抓取方面。然而,与学起来相对容易,但通常以牺牲性能为代价的 Python 不同,Rust 语言可能理解起来有难度。 

这并不意味着无法或者很难用 Rust 编程构建爬虫进行抓取。只有当用户完全不知道如何入手时,使用 Rust 爬虫进行抓取才会具有挑战性。

在本实用教程中,我们将学习如何使用 Rust 编程语言构建网络爬虫,并顺利地从电子商务网站抓取产品数据。这个教程将让您轻松上手 Rust 语言应用场景。 

Rust 语言教程:安装和运行 Rust 语言环境

让我们按照 Rust 安装教程,首先来安装 Rust 程序设计语言。安装方式具体取决于您电脑的操作系统。 

在 Windows 上安装 Rust 语言环境

安装Rust语言环境,首选使用 rustup 实用程序。前往 https://www.rust-lang.org/tools/install 页面。该页面会根据您使用的操作系统显示不同的内容。在 Windows 上,页面将显示如下:

点击 RUSTUP-INIT (64-bit) 按钮下载 rustup 可执行程序。 

重要提示:必须下载安装 Visual Studio C++ Build tools,然后安装 Rust 编程语言和编译器。 

安装 Visual Studio C++ 构建工具后,运行下载的 rustup-init.exe 文件。此程序会打开一个命令提示符窗口,通知您应安装 Visual Studio C++ 构建工具,如下所示:

y 继续安装。在下一个屏幕上,查看信息并按 1 继续安装。

安装完成后,关闭命令提示符并再次打开。打开新的命令提示符可确保所有环境变量更改都生效。

可以运行以下命令来验证安装:

C:\>rustc --version
rustc 1.62.1 (e092d0b6b 2022-07-16)

在 macOS 和 Linux 系统上安装 Rust 语言环境

尽管可以使用 Homebrew 在 macOS 上安装 Rust 语言环境,但我们还是建议使用 rustup 可执行文件。使用 rustup 可以确保正确安装其他必要程序,例如 cargo。

前往 https://www.rust-lang.org/tools/install 页面。在 macOS 和 Linux 上,页面显示如下:

复制 cURL 命令以下载并安装 rustup可执行文件。打开终端并运行此命令。此时将看到确的屏幕:

查看信息并按 1 继续安装。

安装完成后,关闭终端并再次打开。重新打开终端确保所有环境变量更改都生效。

可以运行以下命令来验证安装:

$ rustc --version
rustc 1.63.0 (4b91a6ea7 2022-08-08)

用于抓取书籍数据的 Rust 爬虫

为了解如何使用 Rust 爬虫进行抓取,我们来创建真实的网络抓取项目。 

我们将要抓取站点 https://books.toscrape.com/,这是一个用于学习网络抓取的虚拟书店。 它有电商网店应有的各种基本组件。 

设置

第一步,打开终端或命令提示符并创建一个 Rust 编程项目。我们将使用 Cargo 包管理器来搭建项目结构、下载依赖项、编译并运行项目。

打开终端,然后运行以下命令来初始化空白项目,如下所示:

$ cargo new book_scraper

此命令将创建文件夹 book_scraper 并以 Rust 项目所需的文件和文件夹初始化此文件夹。重要文件包括 Cargo.toml 和 src 文件夹中的 main.rs 文件。

在您选择的文本编辑器或 IDE 中打开此文件夹。 

如果您使用的是 Visual Studio Code,我们建议安装一个扩展组件,例如rust-analyzer,以便在 Visual Studio Code 中使用 Rust 环境进行编码。

现在,打开 Cargo.toml 文件,输入以下代码行:

[dependencies]
reqwest = {version = "0.11", features = ["blocking"]} 
scraper = "0.13.0"

这几行代码表明有两个依赖项 - reqwestscraper。我们稍后再来详细讲解。

返回终端并运行以下命令以下载依赖项并编译代码。

$ cargo build
Finished dev [unoptimized + debuginfo] target(s) in 0.12s
Running `target/debug/book_scraper`
Hello, world!

此命令将编译代码以创建可执行文件并运行此文件。可执行文件创建于以下路径:

./target/debug/book_scraper

如果是 Windows 操作系统,文件名为:

.\target\debug\book_scraper.exe

发送 HTTP 请求

要发送 HTTP 请求、GET 或 POST,我们需要 Rust 库。最方便的 Rust 库就是 reqwest。 

该库可以用于两种类型的 http 客户端(http client):异步 http 客户端和阻塞式 http 客户端。

本文旨在介绍使用 Rust 语言进行抓取的基本概况。因此选择阻塞式客户端更适合,更容易跟上教程。这就是我们在 Cargo.toml 中指定我们需要阻塞式功能的原因。

reqwest = {version = "0.11", features = ["blocking"]} 

打开 main.rs,在 main() 函数中输入以下几行代码:

fn main() {
    let url = "https://books.toscrape.com/";
    let response = reqwest::blocking::get(url).expect("Could not load url.");
    let body = response.text().unwrap();
    print!("{}",body);
}

我们将在第一行代码中存储目标 URL。 

下一行代码是通过阻塞式 http 客户端向此 URL 发送 GET 请求。结果则存储在变量响应中。

之后,从响应中提取 HTML 并将其存储在 body 变量中。这个变量会被打印出来。

保存此文件并在终端输入以下命令行:

$ cargo run

这时输出的是终端上打印的整个 HTML。

用爬虫解析 HTML

要构建网络爬虫,我们需要使用另一个 Rust 库。这个库就被称为 scraper。通过这个库可以使用 CSS 选择器来提取所需的 HTML 元素。

如果您还没有提取,请在依赖项下的 Cargo.toml 文件中输入以下行:

scraper = "0.13.0" 

打开 main.rs 文件并输入以下代码行:

let document = Html::parse_document(&body);

在这一行中,我们调用 parse_document 来解析网页。我们将发送使用 reqwest Rust 库提取的原始 HTML。结果是解析后存储在名为 document 的变量中的文档。

可以使用 CSS 选择器查询已解析的 HTML 文档,以定位包含所需信息的 HTML 元素。 

我们可以将这一流程分解成以下三步:

  • 通过 CSS 选择器定位产品;

  • 提取产品描述;

  • 提取产品链接。

有关更多信息,参见以下各个部分。

通过 CSS 选择器定位产品

第一步是确定包含产品相关信息的CSS选择器。在我们的示例中,产品是一本书。

用 Chrome 浏览器打开 https://books.toscrape.com/,并检查网页的 HTML 标记。

<IMAGE: book_container.png / ALT: Contain for a product and CSS Selector>

您会注意到选择器 article.product_pod 选择了一本书。这说明我们可以对所有这些书籍进行循环并提取个人信息。

首先,在 main.rs 文件的开头添加以下行:

use scraper::{Html, Selector};

接下来,在 main 函数中添加以下行:

 let book_selector = Selector::parse("article.product_pod").unwrap();

现在选择器可以使用了。将以下几行添加到 main 函数中:

for element in document.select(&book_selector) {
// more code here
}

现在我们可以应用更多选择器来提取每本书的信息。

提取产品描述

遍历每个产品描述容器的 HTML 元素,从而轻松编写可重复使用的网页抓取代码。

在此例中,我们要检索产品名称和产品价格。

首先,在 for 循环之前创建两个选择器,如下所示:

let book_name_selector = Selector::parse("h3 a").unwrap();
let book_price_selector = Selector::parse(".price_color").unwrap();

for 循环中,将这些选择器用于每本书:

for element in document.select(&book_selector) {
    let book_name_element = element.select(&book_name_selector).next().expect("Could not select book name.");
    let book_name = book_name_element.value().attr("title").expect("Could not find title attribute.");
    let price_element = element.select(&book_price_selector).next().expect("Could not find price");
    let price = price_element.text().collect::<String>();
   println!("{:?} - {:?}",book_name, price);
}

注意两个要点:

  • 书名在 <a> 元素的 title 属性中;

  • 价格在文本元素中。

保存文件并在终端运行以下命令:

$ cargo run

这时应该在终端上打印书名和价格。

提取产品链接

可用类似方式提取产品链接。在 for 循环外创建一个选择器,如下所示:

let book_link_selector = Selector::parse("h3 a").unwrap();

for 循环中添加以下行:

let book_link_element = element.select(&book_name_selector).next().expect("Could not find book link element.");
let book_link= book_link_element.value().attr("href").expect("Could not find href attribute");

我们抓取的所有值现在都可以打印到控制台。而且我们可以将所有内容保存为 CSV,这一点尤佳。

将抓取数据写入 CSV 文件

不创建文件,任何网络抓取项目都不算完整。因此,我们来编写一个 CSV 文件。

我们使用 CSV Rust 库来创建 CSV 文件。

首先,将以下行添加到 Cargo.toml 依赖项中:

csv="1.1"

然后,在 for 循环之前创建一个 CSV 编写器,如下所示:

let mut wtr = csv::Writer::from_path("books.csv").unwrap();

或者,在 for 循环之前编写标头,如下所示:

wtr.write_record(&["Book Name", "Price", "Link"]).unwrap();

for 循环中,按以下方式编写每条记录:

wtr.write_record([book_name, &price, &book_link]).unwrap();

最后,在 for 循环之后关闭文件:

wtr.flush().expect("Could not close file");

将所有内容归为一处,main.rs 文件包含以下内容:

// main.rs
use scraper::{Html, Selector};
fn main() {
    let url = "https://books.toscrape.com/";
    let response = reqwest::blocking::get(url).expect("Could not load url.");
    let body = response.text().expect("No response body found.");
    let document = Html::parse_document(&body);
    let book_selector = Selector::parse("article.product_pod").expect("Could not create selector.");
    let book_name_selector = Selector::parse("h3 a").expect("Could not create selector.");
    let book_price_selector = Selector::parse(".price_color").expect("Could not create selector.");
    let mut wtr = csv::Writer::from_path("books.csv").expect("Could not create file.");
    wtr.write_record(&["Book Name", "Price", "Link"]).expect("Could not write header.");
    for element in document.select(&book_selector) {
    let book_name_element = element.select(&book_name_selector).next().expect("Could not select book name.");
    let book_name = book_name_element.value().attr("title").expect("Could not find title attribute.");
    let price_element = element.select(&book_price_selector).next().expect("Could not find price");
    let price = price_element.text().collect::<String>();
    let book_link_element = element.select(&book_name_selector).next().expect("Could not find book link element.");
    let book_link= book_link_element.value().attr("href").expect("Could not find href attribute");
    wtr.write_record([book_name, &price, &book_link]).expect("Could not create selector.");
    }
    wtr.flush().expect("Could not close file");
    println!("Done");
} 

总结

本文讲解了如何使用 Rust 语言编写网络爬虫(Rust 爬虫)。我们讨论了如何在 Scraper Rust 库的帮助下,将 CSS 选择器应用于网络爬虫。更多教程,请查看 cURL 博客文章用 RC# 进行网络抓取

常见问题解答

Rust 是什么语言?

Rust 是一种强调安全性和性能的多范式、静态类编程语言。可用它来解决其他计算机语言存在的内存问题和并发编程限制。尽管学起来有些难度,但掌握以后非常实用,因此值得学习。

Rust 语言可以做什么?Rust 语言的用途是什么?

Rust 编程语言可用于内存管理,具有高性能,用途广泛。它可以通过所有权模型确定内存分配,可用于编写并发程序而不会导致数据竞争。 

此外,Rust 可提供极佳用户体验,它丰富的错误消息和更正建议对用户来说十分友好。这样,更易于管理高性能程序编写。

总体而言,Rust 编程语言学习起来相对快速且适应性强较强,活跃的社区和信息丰富的学习文档很有帮助。如果想要绕过其他语言可能存在的安全问题,Rust 语言是很好的解决方案。

关于作者

Maryia Stsiopkina

文案

Maryia Stsiopkina 在 Oxylabs 担任一名初级文案。随着她对写作的热情逐渐发展,她在不同的时间点上不是写令人毛骨悚然的侦探故事,就是写儿童童话故事。最终,她发现自己进入了科技仙境,拥有无数隐藏的领域值得他去探索。在业余时间,她用望远镜观鸟(有些人误以为是跟踪,这就是为什么 Maryia 有时会发现自己处于尴尬的境地),制作花卉饰品,并品尝很多泡菜和绿橄榄。

Oxylabs博客上的所有信息均按“原样”提供,仅供参考。对于您使用Oxylabs博客中包含的任何信息或其中可能链接的任何第三方网站中包含的任何信息,我们不作任何陈述,亦不承担任何责任。在从事任何类型的抓取活动之前,请咨询您的法律顾问,并仔细阅读特定网站的服务条款或取得抓取许可。

在这篇文章


  • Rust 语言教程:安装和运行 Rust 语言环境

  • 用于抓取书籍数据的 Rust 爬虫

  • 总结

选择Oxylabs®,业务更上一层楼


隐私政策

oxylabs.cn© 2023 保留所有权利©