用 Rust 抓取網頁數據
在本文中,我們將學習通過使用 Rust 進行網頁數據抓取,文末有完整代碼。
我們將使用 Rust reqwest 和 scraper 這兩個流行的庫來抓取網站數據,我們將稍微討論一下這些庫。在本文的最後,你將對 Rust 的工作原理以及如何將其用於網絡數據抓取有一個基本的概念。
設置先決條件
首先,我們創建一個 rust 項目:
cargo new rust_tutorial
然後我們必須安裝兩個 Rust 庫,這兩個庫將在本教程中使用。
-
reqwest:它將用於與主機網站建立 HTTP 連接。
-
scraper:它將用於選擇 DOM 元素和解析 HTML。
將它們添加到 Cargo.toml 文件中:
[dependencies]
reqwest = "0.10.8"
scraper = "0.12.0"
tokio = { version = "1.25.0", features = ["full"] }
0.10.8 和 0.12.0 都是庫的最新版本。現在終於可以在項目文件 src/main.rs 中訪問它們了。
抓取什麼?
我們將從 “books.toscrape.com” 網站頁面上抓取每本書的書名和價格。
這個過程很簡單。首先,我們將檢查 chrome 以確定這些元素在 DOM 中的確切位置,然後我們將使用 scraper 庫來解析它們。
抓取單個圖書數據
讓我們一步一步地抓取書名和價格。首先,必須確定 DOM 元素的位置。
正如你在上面所看到的,圖書標題是存儲在標題屬性內的一個標籤。現在讓我們看看價格存儲在哪裏。
價格存儲在類 price_color 的標記下。現在,讓我們用 rust 編寫代碼並提取數據。
第一步是在 src/main.rs 中導入所有相關庫。
use reqwest::Client;
use scraper::{Html, Selector};
使用 reqwest,我們將建立到主機網站的 HTTP 連接,使用 scraper 庫,我們將解析 HTML 內容,我們將通過 reqwest 庫發出 GET 請求。
現在,我們必須創建一個客戶端,用於使用 reqwest 發送連接請求。
let client = Client::new();
最後,我們將使用上面創建的客戶端將 GET 請求發送到目標 URL。
let res = client.get("http://books.toscrape.com/").send().await?;
這裏我們使用 mut 修飾符將值綁定到變量。這提高了代碼的可讀性,一旦你在將來改變了這個值,你可能不得不改變代碼的其他部分。
因此,一旦請求發送,你將得到 HTML 格式的響應。但是你必須使用. text().unwrap() 從 res 變量中提取 HTML 字符串。
let body = res.text().await?;
這裏 res.text().unwrap() 將返回一個 HTML 字符串,我們將該字符串存儲在 body 變量中。
現在,我們有了一個字符串,通過它可以提取我們想要的所有數據。在使用 scraper 庫之前,我們必須使用 Html::parse_document 將此字符串轉換爲 scraper::Html 對象。
let document = Html::parse_document(&body);
現在,這個對象可以用於選擇元素和導航到所需的元素。
首先,讓我們爲書名創建一個選擇器。我們將使用 Selector::parse 函數創建一個 scraper::Selector 對象。
let book_title_selector = Selector::parse("h3 > a").unwrap();
現在可以使用該對象從 HTML 文檔中選擇元素。我們已經將 h3 > a 作爲參數傳遞給解析函數。這是我們感興趣的 CSS 元素選擇器。H3 > a 意味着它將選擇所有的 a 標籤,它們是 H3 標籤的子標籤。
正如你上圖中看到的,目標 a 標記是 h3 標記的子標記。因此,我們在上面的代碼中使用了 h3 > a。
由於有很多的書,我們將使用 for 循環遍歷所有的書。
for book_title in document.select(&book_title_selector) {
let title = book_title.text().collect::<Vec<_>>();
println!("Title: {}", title[0]);
}
select 方法將爲我們提供與選擇器 book_title_selector 匹配的元素列表。然後遍歷該列表以找到 title 屬性並最終打印它。
這裏 Vec<_>> 表示一個動態大小的數組。它是一個向量,你可以通過它在向量中的位置訪問任何元素。
下一步也是最後一步是提取價格。
let book_price_selector = Selector::parse(".price_color").unwrap();
我們再次使用 Selector::parse 函數創建 scraper::Selector 對象。如上所述,價格存儲在 price_color 類下。我們把這個作爲 CSS 選擇器傳遞給了 parse 函數。
然後,我們將再次使用 for 循環,就像我們上面所做的那樣,遍歷所有 price 元素。
for book_price in document.select(&book_price_selector) {
let price = book_price.text().collect::<Vec<_>>();
println!("Price: {}", price[0]);
}
一旦你找到匹配的選擇器,它將獲得文本並打印到控制檯上。
最後,我們完成了可以從目標 URL 提取標題和價格的代碼。現在,一旦你保存這個並使用 cargo run 運行代碼,你將得到類似這樣的輸出。
Title: A Light in the ...
Title: Tipping the Velvet
Title: Soumission
Title: Sharp Objects
Title: Sapiens: A Brief History ...
Title: The Requiem Red
Title: The Dirty Little Secrets ...
Title: The Coming Woman: A ...
Title: The Boys in the ...
Title: The Black Maria
Title: Starving Hearts (Triangular Trade ...
Title: Shakespeare's Sonnets
Title: Set Me Free
Title: Scott Pilgrim's Precious Little ...
Title: Rip it Up and ...
Title: Our Band Could Be ...
Title: Olio
Title: Mesaerion: The Best Science ...
Title: Libertarianism for Beginners
Title: It's Only the Himalayas
Price: £51.77
Price: £53.74
Price: £50.10
Price: £47.82
Price: £54.23
Price: £22.65
Price: £33.34
Price: £17.93
Price: £22.60
Price: £52.15
Price: £13.99
Price: £20.66
Price: £17.46
Price: £52.29
Price: £35.02
Price: £57.25
Price: £23.88
Price: £37.59
Price: £51.33
Price: £45.17
完整代碼
你可以對代碼進行更多更改,以提取其他信息,如星級、圖書圖像等。可以使用相同的技術,首先檢查和查找元素的位置,然後使用 Selector 函數提取它們。
use reqwest::Client;
use scraper::{Html, Selector};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a new client
let client = Client::new();
// Send a GET request to the website
let res = client.get("http://books.toscrape.com/")
.send().await?;
// Extract the HTML from the response
let body = res.text().await?;
// Parse the HTML into a document
let document = Html::parse_document(&body);
// Create a selector for the book titles
let book_title_selector = Selector::parse("h3 > a").unwrap();
// Iterate over the book titles
for book_title in document.select(&book_title_selector) {
let title = book_title.text().collect::<Vec<_>>();
println!("Title: {}", title[0]);
}
// Create a selector for the book prices
let book_price_selector = Selector::parse(".price_color").unwrap();
// Iterate over the book prices
for book_price in document.select(&book_price_selector) {
let price = book_price.text().collect::<Vec<_>>();
println!("Price: {}", price[0]);
}
Ok(())
}
總結
我們學習了 Rust 如何用於網頁抓取。使用 Rust,你也可以抓取許多其他動態網站。即使在上面的代碼中,你也可以做一些更改來抓取圖像和評級。這肯定會提高你的使用 Rust 進行網絡抓取的技能。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/5kwVXFobW1OJ5lU1nn9Vkw