这篇文章是一个简单的Rust爬虫示例,我将爬取该网站的图书信息,包括书名、价格和库存状态。使用reqwest库发送HTTP请求,select库解析HTML内容。代码结构清晰,包含错误处理和基本的数据提取逻辑。
适合Rust爬虫新手学习网络请求、HTML解析和数据提取的基本流程。通过这个示例,你可以了解如何构建一个完整的爬虫工作流。
下面是一个简单、技术成熟且易于理解的 Rust 爬虫教程。我们将创建一个爬取图书信息(标题、价格)的爬虫,目标网站是专为爬虫练习设计的 books.toscrape.com。
项目准备
1、创建新项目:
cargo new book_scraper
cd book_scraper
2、添加依赖 (Cargo.toml):
[dependencies]
reqwest = { version = "0.11", features = ["blocking"] } # 同步HTTP客户端
scraper = "0.13" # HTML解析库
select = "0.5" # CSS选择器库
anyhow = "1.0" # 简化错误处理
完整代码 (src/main.rs)
use anyhow::{Context, Result};
use select::document::Document;
use select::predicate::{Class, Name};
fn main() -> Result<()> {
// 目标网站
let url = "http://books.toscrape.com/";
// 发送HTTP GET请求
let response = reqwest::blocking::get(url)
.with_context(|| format!("Failed to fetch {}", url))?;
// 确保请求成功
if !response.status().is_success() {
anyhow::bail!("Request failed with status: {}", response.status());
}
// 读取HTML内容
let html_content = response.text()
.with_context(|| "Failed to read response body")?;
// 解析HTML文档
let document = Document::from(html_content.as_str());
println!("开始爬取: {}", url);
println!("{:-^50}", "图书列表");
// 查找所有图书条目
for book in document.find(Class("product_pod")) {
// 提取标题
let title = book.find(Name("h3")).next()
.and_then(|h3| h3.find(Name("a")).next())
.map(|a| a.text())
.unwrap_or_else(|| "未知标题".to_string());
// 提取价格
let price = book.find(Class("price_color")).next()
.map(|p| p.text())
.unwrap_or_else(|| "未知价格".to_string());
// 提取库存状态
let stock = book.find(Class("instock")).next()
.map(|s| s.text().trim().to_string())
.unwrap_or_else(|| "未知库存".to_string());
println!("书名: {}", title);
println!("价格: {}", price);
println!("库存: {}", stock);
println!("{}", "-".repeat(40));
}
println!("爬取完成!共找到 {} 本书", document.find(Class("product_pod")).count());
Ok(())
}
代码解析
1、HTTP请求 (reqwest):
let response = reqwest::blocking::get(url)?;
使用同步方式获取网页内容,适合简单爬虫
2、错误处理 (anyhow):
.with_context(|| "错误描述")?;
提供友好的错误信息,自动处理错误传播
3、HTML解析 (select):
let document = Document::from(html_content.as_str());
将HTML内容加载到可查询的文档结构中
4、元素查找:
document.find(Class("product_pod"))
使用CSS选择器查找图书容器
5、数据提取:
book.find(Name("h3")).next().map(|h3| h3.text())
链式调用安全提取元素文本内容
运行结果示例
开始爬取: http://books.toscrape.com/
——————图书列表——————
书名: A Light in the Attic
价格: £51.77
库存: In stock
—————————————-
书名: Tipping the Velvet
价格: £53.74
库存: In stock
—————————————-
… (其他图书) …
书名: The Black Maria
价格: £22.60
库存: In stock
—————————————-
爬取完成!共找到 20 本书
进阶功能添加
1、保存到CSV文件
添加依赖:
csv = "1.1"
修改代码:
use csv::Writer;
// 在main函数开头添加:
let mut wtr = Writer::from_path("books.csv")?;
wtr.write_record(&["书名", "价格", "库存"])?;
// 在循环内替换打印语句为:
wtr.write_record(&[&title, &price, &stock])?;
// 在main函数结尾添加:
wtr.flush()?;
println!("数据已保存到 books.csv");
2、自动翻页
let mut page = 1;
let mut total_books = 0;
loop {
let url = format!("http://books.toscrape.com/catalogue/page-{}.html", page);
// …爬取逻辑…
// 检查是否有下一页
if document.find(Class("next")).next().is_none() {
break;
}
page += 1;
// 添加延时防止请求过快
std::thread::sleep(std::time::Duration::from_secs(1));
}
注意事项
1、尊重网站规则:
- 添加请求延时(至少1秒)
- 检查robots.txt(本例中http://books.toscrape.com/robots.txt允许爬取)
std::thread::sleep(std::time::Duration::from_secs(1));
2、处理异常:
- 网络错误
- HTML结构变化
.unwrap_or_else(|| "未知".to_string());
3、用户代理设置:
let client = reqwest::blocking::Client::builder()
.user_agent("Mozilla/5.0 (学习用爬虫)")
.build()?;
client.get(url).send()?;
这个爬虫包含了爬虫的核心流程:请求 → 解析 → 提取 → 存储,使用成熟稳定的库实现,适合 Rust 新手学习。可根据需求扩展多线程、代理支持等高级功能。
到此就爬取完成!程序统计了找到的图书数量并显示结果。实际应用中,你可以添加CSV保存功能将数据存储到文件,或实现自动翻页爬取全站内容。注意在实际使用时添加请求延时,遵守robots.txt规则,并完善错误处理机制。这个基础爬虫可以扩展为更复杂的项目,如添加代理支持、并发处理或用户登录功能。希望这个示例能帮助你入门Rust爬虫开发!
评论前必须登录!
注册