Rust网页解析与操作库webpage的使用,高效处理HTML解析、DOM操作和网页内容提取
Rust网页解析与操作库webpage的使用,高效处理HTML解析、DOM操作和网页内容提取
小型库,用于获取网页信息:标题、描述、语言、HTTP信息、链接、RSS订阅、Opengraph、Schema.org等
使用方法
use webpage::{Webpage, WebpageOptions};
let info = Webpage::from_url("http://www.rust-lang.org/en-US/", WebpageOptions::default())
.expect("Could not read from URL");
// HTTP传输信息
let http = info.http;
assert_eq!(http.ip, "54.192.129.71".to_string());
assert!(http.headers[0].starts_with("HTTP"));
assert!(http.body.starts_with("<!DOCTYPE html>"));
assert_eq!(http.url, "https://www.rust-lang.org/en-US/".to_string()); // 跟随重定向(HTTPS)
assert_eq!(http.content_type, "text/html".to_string());
// 解析的HTML信息
let html = info.html;
assert_eq!(html.title, Some("The Rust Programming Language".to_string()));
assert_eq!(html.description, Some("A systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety.".to_string()));
assert_eq!(html.opengraph.og_type, "website".to_string());
你也可以获取本地数据的HTML信息:
use webpage::HTML;
let html = HTML::from_file("index.html", None);
// 或者 let html = HTML::from_string(input, None);
完整示例
以下是一个完整的示例,展示如何使用webpage库解析网页并提取各种信息:
use webpage::{Webpage, WebpageOptions};
use std::time::Duration;
fn main() {
// 自定义选项
let mut options = WebpageOptions::default();
options.timeout = Duration::from_secs(15); // 设置超时为15秒
options.useragent = "My Rust Web Scraper".to_string();
// 从URL获取网页信息
let webpage = Webpage::from_url("https://www.example.com", options)
.expect("Failed to fetch webpage");
// 打印HTTP信息
println!("HTTP Info:");
println!("URL: {}", webpage.http.url);
println!("IP: {}", webpage.http.ip);
println!("Response Code: {}", webpage.http.response_code);
println!("Content Type: {}", webpage.http.content_type);
println!("Transfer Time: {:?}", webpage.http.transfer_time);
// 打印HTML信息
println!("\nHTML Info:");
println!("Title: {:?}", webpage.html.title);
println!("Description: {:?}", webpage.html.description);
println!("Language: {:?}", webpage.html.language);
// 打印所有链接
println!("\nLinks ({} found):", webpage.html.links.len());
for (i, link) in webpage.html.links.iter().enumerate().take(5) {
println!("{}. {} -> {}", i + 1, link.text, link.url);
}
// 打印Opengraph信息
println!("\nOpengraph Info:");
println!("Type: {}", webpage.html.opengraph.og_type);
println!("Properties:");
for (key, value) in &webpage.html.opengraph.properties {
println!("- {}: {}", key, value);
}
// 打印Schema.org信息
println!("\nSchema.org Info:");
for schema in &webpage.html.schema_org {
println!("- Type: {}", schema.schema_type);
println!(" Value: {}", schema.value);
}
// 打印纯文本内容(前200个字符)
println!("\nText Content (first 200 chars):");
println!("{}", &webpage.html.text_content[..200.min(webpage.html.text_content.len())]);
}
特性
序列化
如果需要使用serde序列化库提供的数据,你可以在Cargo.toml
中指定serde
特性:
webpage = { version = "2.0", features = ["serde"] }
不依赖curl
默认启用了curl
特性,但是可选的。如果你不需要HTTP客户端但已经有HTML数据在手,这很有用。
所有字段
pub struct Webpage {
pub http: HTTP, // HTTP传输信息
pub html: HTML, // 从解析的HTML文档中获得的信息
}
pub struct HTTP {
pub ip: String,
pub transfer_time: Duration,
pub redirect_count: u32,
pub content_type: String,
pub response_code: u32,
pub headers: Vec<String>, // 最终请求的原始头信息
pub url: String, // 有效URL
pub body: String,
}
pub struct HTML {
pub title: Option<String>,
pub description: Option<String>,
pub url: Option<String>, // 规范URL
pub feed: Option<String>, // 通常是RSS订阅
pub language: Option<String>, // 指定的语言,不是检测的
pub text_content: String, // 从正文中剥离所有标签
pub links: Vec<Link>, // 文档中的所有链接
pub meta: HashMap<String, String>, // 扁平化的元属性列表
pub opengraph: Opengraph,
pub schema_org: Vec<SchemaOrg>,
}
pub struct Link {
pub url: String, // 解析后的链接URL
pub text: String, // 锚文本
}
pub struct Opengraph {
pub og_type: String,
pub properties: HashMap<String, String>,
pub images: Vec<Object>,
pub videos: Vec<Object>,
pub audios: Vec<Object>,
}
// Facebook的Opengraph结构化数据
pub struct OpengraphObject {
pub url: String,
pub properties: HashMap<String, String>,
}
// Google的schema.org结构化数据
pub struct SchemaOrg {
pub schema_type: String,
pub value: serde_json::Value,
}
选项
以下HTTP配置可用:
pub struct WebpageOptions {
allow_insecure: false,
follow_location: true,
max_redirections: 5,
timeout: Duration::from_secs(10),
useragent: "Webpage - Rust crate - https://crates.io/crates/webpage".to_string(),
headers: vec!["X-My-Header: 1234".to_string()],
}
// 使用
let mut options = WebpageOptions::default();
options.allow_insecure = true;
let info = Webpage::from_url(&url, options).expect("Halp, could not fetch");
1 回复
Rust网页解析与操作库webpage使用指南
webpage
是一个Rust库,用于高效解析HTML、操作DOM和提取网页内容。它提供了类似浏览器环境的API来处理网页数据。
主要特性
- HTML解析和DOM构建
- CSS选择器支持
- 网页内容提取
- 表单处理
- 轻量级且高效
基本使用方法
添加依赖
首先在Cargo.toml
中添加依赖:
[dependencies]
webpage = "0.4"
解析HTML文档
use webpage::HTML;
fn main() {
let html = r#"
<html>
<head><title>测试页面</title></head>
<body>
<div id="content">Hello, world!</div>
<a href="/about">关于</a>
</body>
</html>
"#;
let document = HTML::from_string(html, None).unwrap();
// 获取标题
if let Some(title) = document.title() {
println!("页面标题: {}", title);
}
// 通过CSS选择器查找元素
if let Some(div) = document.select("#content").next() {
println!("div内容: {}", div.text());
}
// 获取所有链接
for link in document.select("a[href]") {
println!("链接: {} -> {}", link.text(), link.attr("href").unwrap());
}
}
提取网页内容
use webpage::{HTML, Webpage};
fn main() {
// 从URL加载网页
let webpage = Webpage::from_url("https://example.com", None).unwrap();
// 获取HTML内容
let html = webpage.html();
// 解析HTML
let document = HTML::from_string(&html, None).unwrap();
// 提取所有段落文本
let paragraphs: Vec<String> = document.select("p")
.map(|p| p.text().trim().to_string())
.collect();
println!("找到 {} 个段落:", paragraphs.len());
for (i, p) in paragraphs.iter().enumerate() {
println!("段落 {}: {}", i+1, p);
}
}
表单处理
use webpage::HTML;
fn main() {
let html = r#"
<form action="/submit" method="post">
<input type="text name="username" value="rust_user">
<input type="password" name="password">
<input type="submit" value="登录">
</form>
"#;
let document = HTML::from_string(html, None).unwrap();
if let Some(form) = document.select("form").next() {
println!("表单 action: {}", form.attr("action").unwrap());
println!("表单 method: {}", form.attr("method").unwrap());
// 获取表单数据
let data = form.form_data();
println!("表单数据: {:?}", data);
}
}
高级用法
修改DOM
use webpage::HTML;
fn main() {
let html = "<div id='container'></div>";
let mut document = HTML::from_string(html, None).unwrap();
if let Some(div) = document.select("#container").next() {
// 设置HTML内容
div.set_inner_html("<p>新内容</p>");
// 添加类
div.add_class("highlight");
// 设置属性
div.set_attr("data-version", "1.0");
}
println!("修改后的HTML:\n{}", document.to_string());
}
处理真实网页
use webpage::{Webpage, WebpageOptions};
fn main() {
let options = WebpageOptions {
enable_javascript: false, // 禁用JS执行
..Default::default()
};
match Webpage::from_url("https://news.ycombinator.com", Some(options)) {
Ok(webpage) => {
let html = webpage.html();
let document = HTML::from_string(&html, None).unwrap();
// 提取新闻标题
let titles: Vec<String> = document.select(".titleline > a")
.map(|a| a.text().trim().to_string())
.collect();
println!("热门新闻:");
for (i, title) in titles.iter().take(10).enumerate() {
println!("{}. {}", i+1, title);
}
}
Err(e) => eprintln!("错误: {}", e),
}
}
性能提示
- 对于大型HTML文档,优先使用迭代器方法(
select().next()
)而不是收集所有结果 - 如果只需要部分内容,考虑使用
WebpageOptions
限制加载的资源 - 重复使用的选择器可以编译为
Selector
对象提高性能
use webpage::{HTML, Selector};
fn main() {
let html = "<div class='item'>Item 1</div><div class='item'>Item 2</div>";
let document = HTML::from_string(html, None).unwrap();
// 预编译选择器
let selector = Selector::parse(".item").unwrap();
for item in document.select(&selector) {
println!("找到项目: {}", item.text());
}
}
完整示例demo
下面是一个完整的webpage库使用示例,展示如何从网页提取数据并修改DOM:
use webpage::{HTML, Webpage, WebpageOptions, Selector};
fn main() {
// 示例1: 解析HTML字符串
println!("=== 示例1: 解析HTML字符串 ===");
let html = r#"
<html>
<head><title>示例页面</title></head>
<body>
<h1>欢迎</h1>
<div class="articles">
<article><h2>文章1</h2><p>内容1</p></article>
<article><h2>文章2</h2><p>内容2</p></article>
</div>
<footer>页脚内容</footer>
</body>
</html>
"#;
let document = HTML::from_string(html, None).unwrap();
// 提取文章标题
let article_titles: Vec<_> = document.select("article h2")
.map(|h2| h2.text().trim().to_string())
.collect();
println!("文章标题: {:?}", article_titles);
// 示例2: 从URL加载并处理网页
println!("\n=== 示例2: 从URL加载网页 ===");
let options = WebpageOptions {
enable_javascript: false,
..Default::default()
};
if let Ok(webpage) = Webpage::from_url("https://example.com", Some(options)) {
let html = webpage.html();
let document = HTML::from_string(&html, None).unwrap();
// 使用预编译选择器
let selector = Selector::parse("h1").unwrap();
if let Some(h1) = document.select(&selector).next() {
println!("主标题: {}", h1.text());
}
}
// 示例3: 修改DOM
println!("\n=== 示例3: 修改DOM ===");
let html = r#"<div id="app"><p>原始内容</p></div>"#;
let mut document = HTML::from_string(html, None).unwrap();
if let Some(div) = document.select("#app").next() {
// 修改内容
div.set_inner_html("<p>修改后的内容</p>");
// 添加属性
div.set_attr("data-modified", "true");
println!("修改后的HTML:\n{}", document.to_string());
}
}
这个完整示例展示了:
- 从HTML字符串解析文档
- 从URL加载网页内容
- 使用CSS选择器提取特定元素
- 预编译选择器提高性能
- 修改DOM元素的内容和属性
webpage
库为Rust开发者提供了强大的网页处理能力,适合爬虫、内容分析和自动化测试等场景。