在本教程中,您将深入了解 Rust 网络爬取。具体来说,您将学到:

  • 为什么 Rust 是一种高效爬取 Web 的优秀语言。
  • Rust 中最好的爬取库是什么。
  • 如何从头开始构建 Rust 爬虫。

让我们深入了解一下!


你能用 Rust 执行网页爬取吗?

当然可以,而且 Rust 还是一个非常有效的选择!

Rust 是一种静态类型的编程语言,以其注重安全性、性能和并发性而闻名。近年来,它因其高效率而受到了广泛关注。这使得它成为各种应用程序的优秀选择,包括网络爬虫。

具体而言,Rust提供了用于在线数据爬取任务的有用功能。例如,其可靠的并发模型允许同时执行多个网络请求。这就是为什么Rust是一种适用于高效地从多个网站上爬取大量数据的通用语言。

此外,Rust生态系统还包括HTTP客户端和HTML解析库,简化了网页检索和数据提取过程。让我们来探索一些最受欢迎的库!


最好的 Rust 网页爬取库

以下是一些最好的 Rust 网页爬取库的列表:

  • reqwest:一个强大的 Rust HTTP 客户端库。它提供了一个简单高效的 API 来发出 HTTP 请求。多亏了它,您可以下载网页、处理 cookie 和自定义标头,使其成为在爬取项目中获取 Web 内容的重要库。
  • scraper:一个简化 HTML 解析和数据提取的 Rust 库。它使您能够通过 CSS 选择器通过内置方法遍历和操作 HTML 文档。
  • rust-headless-chrome:一个 Rust 库,它公开了一个高级 API,用于通过 DevTools 协议控制 Chrome 的无头实例。您可以将其视为 Rust 中的 Puppeteer。这是处理涉及需要 JavaScript 渲染或浏览器自动化的动态页面的爬取任务的不可或缺的工具。

先决条件

要遵循此网页爬取 Rust 教程,您需要在计算机上安装 Rust。在终端中启动以下命令以验证:

rustc --version

如果结果如下,那么你就可以开始了:

rustc 1.73.0 (cc66ad468 2023-10-03)

如果以错误结束,则需要安装 Rust。 从官方网站下载安装程序并按照说明进行操作。这将设置:

  • rustup:Rust 工具链管理器
  • cargo:Rust 包管理器。

您知道需要一个 IDE 来使用 Rust 进行编码。安装了 rust-analyzer 扩展 的 Visual Studio Code 是一款免费且可靠的解决方案。


用 Rust 构建网络爬虫

在本分步部分中,您将了解如何构建 Rust 网络爬取工具。您将编写一个自动化脚本,该脚本可以自动从Quotes scraping sandbox检索数据。 Rust 网络爬取过程的目标是:

  1. 从页面中选择引用 HTML 元素。
  2. 从中提取数据。
  3. 将收集的数据转换为易于探索的格式,例如 CSV。

截至撰写本文时,目标站点如下所示:

转换收集到的数据

请按照以下说明学习如何在 Rust 中执行网页爬取!

第 1 步:在 Rust 中建立一个项目

是时候初始化 Rust 网络爬取项目了。在要放置项目的文件夹中打开终端,然后运行以下命令:

cargo new rust_web_scraper

将出现 rust_web_scraper 目录。打开它你会看到:

  • toml:manifest 文件,包含项目的依赖项。
  • src/:包含 Rust 文件的文件夹。

在 IDE 中打开 rust_web_scraper 文件夹。您会注意到 src 目录中的 main.rs 文件包含:

fn main() {

println!("Hello, world!");

}

这就是最简单的 Rust 脚本的样子。 main() 函数代表任何 Rust 应用程序的入口点。

完美,验证您的脚本是否有效!

在 IDE 的终端中,执行以下命令来编译 Rust 应用程序:

cargo build

这应该在目标文件夹中创建一个二进制文件。

您现在可以使用以下命令运行二进制可执行文件:

cargo run

如果一切按预期进行,它应该在终端中打印:

Hello, World!

太好了,您现在有了一个可以运行的 Rust 项目!现在,您的爬取工具只需打印“Hello, World!”但它很快就会包含一些爬取逻辑。

第2步:安装项目的依赖项

在安装任何软件包之前,您需要确定哪些 Rust 网络爬取库最适合您的目标。为此,请在浏览器中打开目标站点。右键单击并选择“Inspect”选项以打开 DevTools。然后,到达“网络”选项卡,重新加载页面,然后查看“Fetch/XHR”部分。

安装项目的依赖项

如您所见,网页不执行任何AJAX 请求。换句话说,它不会在客户端上动态检索数据。因此,它是一个静态页面,其 HTML 内容已包含所有数据。

因此,您不需要具有无头浏览器功能的库来对其执行网页爬取。您仍然可以使用 Headless Chrome,但这只会带来性能开销。这就是为什么你应该这样做:

  • reqwest:作为 HTTP 客户端检索与目标页面关联的 HTML 文档。
  • scraper:作为 HTML 解析器来解析 HTML 内容并从中检索数据。

将 reqwest 和 scraper 添加到项目的依赖项中:

cargo add scraper reqwest --features "reqwest/blocking"

该命令将相应地更新 Cargo.toml 文件。

做得好!您现在已经具备了在 Rust 中执行数据爬取所需的一切!

第三步:下载目标页面

使用reqwest的阻塞HTTP客户端下载目标页面的HTML文档:

let response = reqwest::blocking::get("https://quotes.toscrape.com/");

let html = response.unwrap().text().unwrap();

在后台,get() 对作为参数传递的 URL 执行同步 HTTP GET 请求。脚本执行将停止,直到服务器响应。

要从响应中以字符串形式提取原始 HTML,您需要调用 unwrap() 两次以:

  1. 解开存储在响应变量中的 Result 对象。如果请求成功,您将收到服务器返回的响应。否则,这将导致 Rust 恐慌
  2. 解开其文本内容以访问 HTML 内容。

第四步:解析HTML文档

现在您已将目标页面的 HTML 内容存储在字符串中,您可以将其提供给 scraper:

let document = scraper::Html::parse_document(&html)

文档对象公开了 HTML 解析器公开的数据提取 API。

您的 main.rs 文件现在应如下所示:

fn main() {

// download the HTML document associated with the target page

let response = reqwest::blocking::get("https://quotes.toscrape.com/");

// extract the raw HTML from the response

let html = response.unwrap().text().unwrap();

// parse the HTML content

let document = scraper::Html::parse_document(&html);

// scraping logic...

}

第五步:检查页面内容

是时候分析目标 URL 的结构以设计有效的数据检索策略了。

在浏览器中打开要爬取的报价。您将看到报价列表。右键单击这些元素之一并选择“检查”。您的浏览器的开发工具将打开如下:

爬取的报价

在那里,您可以注意到每个报价卡都是一个 .quote HTML 节点,其中包含:

  1. 存储引用文本的 .text 元素。
  2. 包含作者姓名的 .author 元素。
  3. 许多 .tag 元素,每个元素显示一个标签。

以上注释包含选择所需 DOM 元素所需的所有CSS 选择器。现在您需要在代码中使用它们来执行 Rust 网页爬取!

第 6 步:实施数据爬取

开始之前,您需要一个自定义数据结构来存储爬取的数据。在 main.rs 文件顶部添加以下行以定义新的 struct

struct Quote {

quote: Option<String>,

author: Option<String>,

tags: Vec<String>,

}

由于页面包含多个引号,因此在 main() 中实例化 Vec 的 Quote 对象:

let mut quotes: Vec<Quote> = Vec::new();

在脚本末尾,引号将包含所有爬取的数据。

了解如何填充该数组!

在 scraper 中定义 CSS Selector 对象,如下所示:

let html_quote_selector = scraper::Selector::parse(".quote").unwrap();

接下来,使用 select() 方法应用于页面并检索所需的 HTML 元素:

let html_quotes = document.select(&html_quote_selector);

您现在可以迭代每个报价元素并从中提取感兴趣的数据:

for html_quote in html_quotes {

let quote_selector = scraper::Selector::parse(".text").unwrap();

let quote = html_quote

.select("e_selector)

.next()

.map(|element| element.text().collect::<String>());




let author_selector = scraper::Selector::parse(".author").unwrap();

let author = html_quote

.select(&author_selector)

.next()

.map(|element| element.text().collect::<String>());




let tags_selector = scraper::Selector::parse(".tag").unwrap();

let tags = html_quote

.select(&tags_selector)

.map(|element| element.text().collect::<String>())

.collect();




// create a new quote object with the scraped data

// and store it in the list

let quote_obj = Quote {

quote,

author,

tags,

};

quotes.push(quote_obj);

}

前几行应用了上面看到的相同方法。他们定义了一个 CSS 选择器对象并将其应用到 quote HTML 元素上。由于 select() 返回多个元素,因此您可以使用 next() 获取第一个元素。然后,text() 方法使您可以访问其文本内容。

获取爬取数据后,只需填充新的 Quote 对象并将其添加到数组中即可。

极好的!您刚刚学习了如何在 Rust 中执行网页爬取!

第七步:添加爬取逻辑

您刚刚从单个页面中提取了数据,但不要忘记报价列表由多个页面组成。特别是,每个页面都有一个“下一步 →”按钮,其中包含指向下一页的链接:

添加爬取逻辑

除最后一页外,所有页面均如此:

除最后一页外,所有页面均如此

要执行网络爬行并从每个页面爬取数据,您需要:

  1. 刮一页。
  2. 查看页面上是否存在“下一步→”元素。
  3. 如果是这样,请跟踪其 URL 并为新页面重复该循环。否则,停止爬取逻辑。

在 Rust 中实现上述算法如下:

// the URL of the first page to scrape

let mut url = "https://quotes.toscrape.com/".to_owned();

loop {

// download the HTML document associated with the target page

let response = reqwest::blocking::get(url);




// parsing and scraping logic...




// select the "Next ->" element

let next_page_element_selector = scraper::Selector::parse(".next").unwrap();

let next_page_element = document.select(&next_page_element_selector).next();




// if this is not the last page

if next_page_element.is_some() {

// retrieve the relative URL to the next page

let next_page_link_selector = scraper::Selector::parse("a").unwrap();

let partial_url = next_page_element

.unwrap()

.select(&next_page_link_selector)

.next()

.and_then(|a| a.value().attr("href"))

.map(str::to_owned)

.unwrap();




// the next page to scrape

url = format!("https://quotes.toscrape.com{partial_url}");

} else {

break;

}

}

Rust 数据爬取逻辑已完成!

步骤 8:将提取的数据导出到 CSV

爬取的数据现在存储在 Rust 对象中。您需要将其转换为不同的格式,以便团队的其他成员更容易阅读和使用。了解如何将收集的数据导出到 CSV 文件。

您可以创建一个 CSV 文件并使用普通 Rust 进行填充,但是 CSV 库让一切变得更加简单。安装它:

货物添加 csv

您现在只需几行代码即可将报价转换为 CSV 文件:

// initialize the CSV output file

let path = std::path::Path::new("quotes.csv");




let mut writer = csv::Writer::from_path(path).unwrap();

// append the header to the CSV

writer.write_record(&["quote", "author", "tags"]).unwrap();




// populate the CSV file

for quote_obj in quotes {

// if the "quote" and "author" fields are not None

if let (Some(quote), Some(author)) = (quote_obj.quote, quote_obj.author) {

let tags = quote_obj.tags.join("; ");

writer.write_record(&[quote, author, tags]).unwrap();

}

}

// free up the writer resources

writer.flush().unwrap();

The above snippet initializes a CSV file with the header row. Then, it iterates over the array of quotes, converts each element to records in CSV formats, and appends it to the output file.

第 9 步:将它们放在一起

以下是 Rust 爬虫的完整代码:

// define a custom data structure

// where to store the scraped data

struct Quote {

quote: Option<String>,

author: Option<String>,

tags: Vec<String>,

}




fn main() {

// initialize the vector that will store the objects

// with the scraped quotes

let mut quotes: Vec<Quote> = Vec::new();




// the URL of the first page to scrape

let mut url = "https://quotes.toscrape.com/".to_owned();




loop {

// download the HTML document associated with the target page

let response = reqwest::blocking::get(url);




// extract the raw HTML from the response

let html = response.unwrap().text().unwrap();

// parse the HTML content

let document = scraper::Html::parse_document(&html);




// select all quote HTML elements on the page

let html_quote_selector = scraper::Selector::parse(".quote").unwrap();

let html_quotes = document.select(&html_quote_selector);




// iterate over each HTML quote to extract data

for html_quote in html_quotes {

// data scraping logic

let quote_selector = scraper::Selector::parse(".text").unwrap();

let quote = html_quote

.select("e_selector)

.next()

.map(|element| element.text().collect::<String>());




let author_selector = scraper::Selector::parse(".author").unwrap();

let author = html_quote

.select(&author_selector)

.next()

.map(|element| element.text().collect::<String>());




let tags_selector = scraper::Selector::parse(".tag").unwrap();

let tags = html_quote

.select(&tags_selector)

.map(|element| element.text().collect::<String>())

.collect();




// create a new quote object with the scraped data

// and store it in the list

let quote_obj = Quote {

quote,

author,

tags,

};

quotes.push(quote_obj);

}




// select the "Next ->" element

let next_page_element_selector = scraper::Selector::parse(".next").unwrap();

let next_page_element = document.select(&next_page_element_selector).next();




// if this is not the last page

if next_page_element.is_some() {

// retrieve the relative URL to the next page

let next_page_link_selector = scraper::Selector::parse("a").unwrap();

let partial_url = next_page_element

.unwrap()

.select(&next_page_link_selector)

.next()

.and_then(|a| a.value().attr("href"))

.map(str::to_owned)

.unwrap();




// the next page to scrape

url = format!("https://quotes.toscrape.com{partial_url}");

} else {

break;

}

}




// initialize the CSV output file

let path = std::path::Path::new("quotes.csv");




let mut writer = csv::Writer::from_path(path).unwrap();

// append the header to the CSV

writer.write_record(&["quote", "author", "tags"]).unwrap();




// populate the CSV file

for quote_obj in quotes {

// if the "quote" and "author" fields are not None

if let (Some(quote), Some(author)) = (quote_obj.quote, quote_obj.author) {

let tags = quote_obj.tags.join("; ");

writer.write_record(&[quote, author, tags]).unwrap();

}

}




// free up the writer resources

writer.flush().unwrap();

}

只需大约 100 行代码,您就可以在 Rust 中构建一个数据爬取器!

使用以下命令编译应用程序:

cargo build

然后,运行它:

cargo run

当 Rust 爬取器从每个页面检索数据时,请保持耐心。当它终止时,quotes.csv 文件将出现在项目的根文件夹中。打开它,您应该看到以下数据:

锈刮刀

瞧!您从在线页面中的非结构化数据开始,现在将其保存在一个方便的 CSV 文件中!


结    论

在本指南中,您了解到为什么Rust是一种用于网络爬虫的高效语言。您还有机会探索一些最好的爬取库。然后,您学习了如何使用它们创建一个能够从真实目标提取数据的Rust爬虫。正如您所见,使用Rust进行网页爬取非常简单,并且只需要几行代码。

主要问题由反机器人和反爬虫系统构成,这些系统被网站采用以保护其数据。这些解决方案可以检测并阻止您的爬取脚本。幸运的是,Bright Data为您提供了一套解决方案:

  • Web Scraper IDE:用于构建网络爬取工具的云 IDE,可以自动绕过和避免任何阻止。
  • Scraping Browser:基于云的可控浏览器,提供 JavaScript 渲染功能,同时为您处理验证码、浏览器指纹识别、自动重试等。它与最流行的自动化浏览器库集成,例如 Playwright 和 Puppeteer。
  • Web Unlocker:一种解锁 API,可以无缝返回任何页面的原始 HTML,规避任何反爬取措施。

如果您不想完全处理网络爬取但仍对在线数据感兴趣,请探索 Bright Data 的即用型数据集

这篇文章有用吗?

点击星号为它评分!

平均评分 / 5. 投票数:

到目前为止还没有投票!成为第一位评论此文章。

No more articles