Rust的robots.txt解析库robotstxt的使用:高效解析与生成网站爬虫规则文件
robotstxt
Google的robots.txt解析器和匹配器C++库的原生Rust移植版本。
- 原生Rust移植,无第三方crate依赖
- 零不安全代码
- 保留原始库的所有行为
- 与原始库一致的API
- 100%通过Google原始测试
安装
[dependencies]
robotstxt = "0.3.0"
快速开始
use robotstxt::DefaultMatcher;
let mut matcher = DefaultMatcher::default();
let robots_body = “user-agent: FooBot\n
disallow: /\n”;
assert_eq!(false, matcher.one_agent_allowed_by_robots(robots_body, “FooBot”, “https://foo.com/”));
关于
引用自Google的robots.txt解析器和匹配器仓库的README:
机器人排除协议(REP)是一种标准,使网站所有者能够通过具有特定语法的简单文本文件控制哪些URL可以被自动化客户端(即爬虫)访问。它是我们所知的互联网的基本构建块之一,也是搜索引擎能够运行的原因。
由于REP在过去25年中只是一个事实上的标准,不同的实现者对robots.txt的解析略有不同,导致混淆。这个项目旨在通过发布Google使用的解析器来解决这个问题。
该库是Googlebot(Google的爬虫)使用的生产代码的略微修改版本(即一些内部头和等效符号),用于根据网站管理员在robots.txt文件中提供的规则确定可以访问哪些URL。该库以开源形式发布,以帮助开发人员构建更好地反映Google的robots.txt解析和匹配的工具。
Crate robotstxt 旨在成为Google的robots.txt解析器和匹配器从C++到Rust的忠实转换。
测试
$ git clone https://github.com/Folyd/robotstxt
Cloning into 'robotstxt'...
$ cd robotstxt/tests
...
$ mkdir c-build && cd c-build
...
$ cmake ..
...
$ make
...
$ make test
Running tests...
Test project ~/robotstxt/tests/c-build
Start 1: robots-test
1/1 Test #1: robots-test ...................... Passed 0.33 sec
许可证
robotstxt解析器和匹配器Rust库根据Apache许可证的条款进行许可。有关更多信息,请参阅LICENSE。
完整示例代码
// 引入robotstxt库中的DefaultMatcher
use robotstxt::DefaultMatcher;
fn main() {
// 创建默认的匹配器实例
let mut matcher = DefaultMatcher::default();
<span class="hljs-comment">// 定义robots.txt内容,禁止FooBot访问所有路径</span>
<span class="hljs-keyword">let</span> <span class="hljs-variable">robots_body</span> = <span class="hljs-string">"user-agent: FooBot\n\
disallow: /\n"</span>;
<span class="hljs-comment">// 检查FooBot是否被允许访问指定URL</span>
<span class="hljs-keyword">let</span> <span class="hljs-variable">is_allowed</span> = matcher.<span class="hljs-title function_ invoke__">one_agent_allowed_by_robots</span>(
robots_body,
<span class="hljs-string">"FooBot"</span>,
<span class="hljs-string">"https://foo.com/"</span>
);
<span class="hljs-comment">// 断言结果应为false(不允许访问)</span>
<span class="hljs-built_in">assert_eq!</span>(<span class="hljs-literal">false</span>, is_allowed);
<span class="hljs-built_in">println!</span>(<span class="hljs-string">"FooBot访问被拒绝: {}"</span>, !is_allowed);
<span class="hljs-comment">// 另一个示例:允许其他爬虫访问</span>
<span class="hljs-keyword">let</span> <span class="hljs-variable">is_other_allowed</span> = matcher.<span class="hljs-title function_ invoke__">one_agent_allowed_by_robots</span>(
robots_body,
<span class="hljs-string">"OtherBot"</span>,
<span class="hljs-string">"https://foo.com/"</span>
);
<span class="hljs-built_in">println!</span>(<span class="hljs-string">"OtherBot访问允许: {}"</span>, is_other_allowed);
}
Rust的robots.txt解析库robotstxt使用指南
概述
robotstxt是一个用于解析和生成robots.txt文件的Rust库,帮助开发者处理网站爬虫规则。该库支持解析现有的robots.txt文件,也能生成符合标准的规则文件。
安装方法
在Cargo.toml中添加依赖:
[dependencies]
robotstxt = "0.10"
基本用法
解析robots.txt文件
use robotstxt::DefaultMatcher;
fn main() {
let contents = r#"
User-agent: *
Disallow: /private/
Allow: /public/
Crawl-delay: 5
"#;
let matcher = DefaultMatcher::default();
let result = matcher.one_agent_allowed_by_robots(contents, "MyBot", "/public/about.html");
println!("允许访问: {}", result); // 输出: true
}
检查特定路径的访问权限
use robotstxt::DefaultMatcher;
fn check_access(robots_txt: &str, user_agent: &str, path: &str) -> bool {
let matcher = DefaultMatcher::default();
matcher.one_agent_allowed_by_robots(robots_txt, user_agent, path)
}
// 使用示例
let robots_content = "
User-agent: Googlebot
Disallow: /private/
User-agent: *
Disallow: /admin/
";
println!("Googlebot访问/admin/: {}",
check_access(robots_content, "Googlebot", "/admin/")); // false
println!("OtherBot访问/admin/: {}",
check_access(robots_content, "OtherBot", "/admin/")); // false
生成robots.txt文件
use robotstxt::RobotsBuilder;
fn generate_robots_txt() -> String {
RobotsBuilder::new()
.add_user_agent("*")
.disallow("/private/")
.allow("/public/")
.crawl_delay(10)
.add_user_agent("Googlebot")
.disallow("/temp/")
.finish()
.to_string()
}
println!("{}", generate_robots_txt());
高级功能
处理多个User-agent
use robotstxt::DefaultMatcher;
fn check_multiple_agents() {
let robots_txt = "
User-agent: Bot1
Disallow: /dir1/
User-agent: Bot2
Allow: /dir1/
Disallow: /dir2/
";
let matcher = DefaultMatcher::default();
// 检查Bot1对/dir1/page的访问
let result1 = matcher.one_agent_allowed_by_robots(robots_txt, "Bot1", "/dir1/page.html");
println!("Bot1访问/dir1/page.html: {}", result1); // false
// 检查Bot2对/dir1/page的访问
let result2 = matcher.one_agent_allowed_by_robots(robots_txt, "Bot2", "/dir1/page.html");
println!("Bot2访问/dir1/page.html: {}", result2); // true
}
处理爬虫延迟设置
use robotstxt::{DefaultMatcher, RobotsParseHandler};
fn get_crawl_delay(robots_txt: &str, user_agent: &str) -> Option<u64> {
let mut handler = RobotsParseHandler::new();
handler.parse(robots_txt.as_bytes());
for group in handler.get_groups() {
if group.applies_to(user_agent) {
return group.get_crawl_delay();
}
}
None
}
let delay = get_crawl_delay(
"User-agent: *\nCrawl-delay: 5",
"MyBot"
);
println!("爬虫延迟: {:?}秒", delay); // Some(5)
错误处理
use robotstxt::DefaultMatcher;
fn safe_check(robots_txt: &str, user_agent: &str, path: &str) -> Result<bool, &'static str> {
if robots_txt.is_empty() {
return Err("空的robots.txt内容");
}
let matcher = DefaultMatcher::default();
Ok(matcher.one_agent_allowed_by_robots(robots_txt, user_agent, path))
}
实际应用示例
use robotstxt::DefaultMatcher;
use reqwest::blocking::get;
fn check_website_permission(url: &str, user_agent: &str, path: &str) -> bool {
let robots_url = format!("{}/robots.txt", url.trim_end_matches('/'));
match get(&robots_url) {
Ok(response) => {
if let Ok(content) = response.text() {
let matcher = DefaultMatcher::default();
matcher.one_agent_allowed_by_robots(&content, user_agent, path)
} else {
true // 如果无法读取内容,默认允许访问
}
}
Err(_) => true // 如果无法获取robots.txt,默认允许访问
}
}
完整示例demo
// 完整示例:构建一个robots.txt检查工具
use robotstxt::{DefaultMatcher, RobotsBuilder};
use std::io::{self, Write};
fn main() {
// 示例1:生成robots.txt文件
println!("=== 生成robots.txt示例 ===");
let robots_content = generate_robots_example();
println!("生成的robots.txt内容:\n{}", robots_content);
// 示例2:检查访问权限
println!("\n=== 访问权限检查示例 ===");
check_access_permissions(&robots_content);
// 示例3:交互式检查工具
println!("\n=== 交互式检查工具 ===");
interactive_check_tool(&robots_content);
}
// 生成示例robots.txt
fn generate_robots_example() -> String {
RobotsBuilder::new()
.add_user_agent("*")
.disallow("/admin/")
.disallow("/private/")
.allow("/public/")
.crawl_delay(5)
.add_user_agent("Googlebot")
.allow("/news/")
.disallow("/temp/")
.add_user_agent("Bingbot")
.disallow("/search/")
.finish()
.to_string()
}
// 检查不同用户代理的访问权限
fn check_access_permissions(robots_txt: &str) {
let matcher = DefaultMatcher::default();
let test_cases = vec![
("Googlebot", "/news/article1", "Googlebot访问新闻文章"),
("Googlebot", "/admin/dashboard", "Googlebot访问管理面板"),
("Bingbot", "/search/results", "Bingbot访问搜索结果"),
("MyCrawler", "/public/docs", "普通爬虫访问公开文档"),
("MyCrawler", "/private/data", "普通爬虫访问私有数据"),
];
for (ua, path, description) in test_cases {
let allowed = matcher.one_agent_allowed_by_robots(robots_txt, ua, path);
println!("{}: {}", description, if allowed { "允许" } else { "拒绝" });
}
}
// 交互式检查工具
fn interactive_check_tool(robots_txt: &str) {
let matcher = DefaultMatcher::default();
loop {
print!("请输入用户代理名称 (输入 'quit' 退出): ");
io::stdout().flush().unwrap();
let mut user_agent = String::new();
io::stdin().read_line(&mut user_agent).unwrap();
let user_agent = user_agent.trim();
if user_agent.eq_ignore_ascii_case("quit") {
break;
}
print!("请输入要检查的路径: ");
io::stdout().flush().unwrap();
let mut path = String::new();
io::stdin().read_line(&mut path).unwrap();
let path = path.trim();
let allowed = matcher.one_agent_allowed_by_robots(robots_txt, user_agent, path);
println!("用户代理 '{}' 访问路径 '{}': {}",
user_agent, path,
if allowed { "允许" } else { "拒绝" }
);
println!();
}
}
这个库提供了完整的robots.txt处理功能,适合在爬虫项目或web应用中集成机器人协议检查功能。