Rust浏览器自动化插件库re_redap_browser的使用,高效实现网页抓取与自动化测试

Rust浏览器自动化插件库re_redap_browser的使用,高效实现网页抓取与自动化测试

re_redap_browser是rerun系列crate的一部分,用于实现浏览器自动化功能。

Latest version Documentation MIT Apache

安装

在项目目录中运行以下Cargo命令:

cargo add re_redap_browser

或在Cargo.toml中添加以下行:

re_redap_browser = "0.24.0"

基本示例

以下是使用re_redap_browser进行网页抓取和自动化测试的完整示例:

use re_redap_browser::Browser;
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // 创建浏览器实例
    let browser = Browser::new().await?;
    
    // 导航到目标网页
    browser.goto("https://example.com").await?;
    
    // 获取网页标题
    let title = browser.title().await?;
    println!("网页标题: {}", title);
    
    // 查找元素并点击
    if let Ok(button) = browser.find_element("button#submit").await {
        button.click().await?;
        println!("已点击提交按钮");
    }
    
    // 获取元素文本内容
    if let Ok(element) = browser.find_element("div.content").await {
        let text = element.text().await?;
        println!("内容文本: {}", text);
    }
    
    // 截图保存
    browser.screenshot("screenshot.png").await?;
    println!("已保存截图");
    
    // 执行JavaScript
    let result: String = browser.execute_script("return document.readyState").await?;
    println!("文档状态: {}", result);
    
    Ok(())
}

高级自动化测试示例

use re_redap_browser::Browser;
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // 初始化浏览器,可配置选项
    let browser = Browser::builder()
        .headless(true)  // 无头模式
        .user_agent("MyCustomAgent/1.0")
        .build()
        .await?;
    
    // 测试登录流程
    browser.goto("https://example.com/login").await?;
    
    // 填写表单
    browser.find_element("input#username").await?.send_keys("testuser").await?;
    browser.find_element("input#password").await?.send_keys("password123").await?;
    
    // 提交表单
    browser.find_element("button#login").await?.click().await?;
    
    // 等待导航完成并验证
    browser.wait_for_navigation().await?;
    assert!(browser.current_url().await?.contains("dashboard"));
    
    // 验证登录成功
    let welcome_msg = browser.find_element("div.welcome").await?.text().await?;
    assert!(welcome_msg.contains("Welcome, testuser"));
    
    // 测试注销功能
    browser.find_element("a#logout").await?.click().await?;
    browser.wait_for_navigation().await?;
    assert!(browser.current_url().await?.contains("login"));
    
    Ok(())
}

网页抓取示例

use re_redap_browser::Browser;
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let browser = Browser::new().await?;
    browser.goto("https://news.ycombinator.com").await?;
    
    // 获取所有新闻条目
    let stories = browser.find_elements("tr.athing").await?;
    
    for story in stories {
        // 获取标题和链接
        let title_element = story.find_element("span.titleline > a").await?;
        let title = title_element.text().await?;
        let url = title_element.attribute("href").await?;
        
        // 获取分数
        let score = story.find_element("span.score").await?.text().await?;
        
        println!("标题: {}", title);
        println!("链接: {}", url.unwrap_or_default());
        println!("分数: {}", score);
        println!("------");
    }
    
    Ok(())
}

完整示例代码

以下是一个结合了网页抓取和自动化测试功能的完整示例:

use re_redap_browser::Browser;
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // 初始化浏览器配置
    let browser = Browser::builder()
        .headless(false)  // 可视化模式
        .build()
        .await?;
    
    // 测试电商网站功能
    println!("开始测试电商网站...");
    browser.goto("https://demo.ecommerce.com").await?;
    
    // 验证首页加载
    let title = browser.title().await?;
    assert!(title.contains("E-Commerce Demo"));
    println!("首页加载成功: {}", title);
    
    // 搜索商品
    browser.find_element("input#search").await?.send_keys("Rust编程书").await?;
    browser.find_element("button#search-btn").await?.click().await?;
    browser.wait_for_navigation().await?;
    
    // 获取搜索结果
    let products = browser.find_elements("div.product-item").await?;
    println!("找到 {} 个商品", products.len());
    
    // 点击第一个商品
    if !products.is_empty() {
        products[0].find_element("a").await?.click().await?;
        browser.wait_for_navigation().await?;
        
        // 添加到购物车
        browser.find_element("button#add-to-cart").await?.click().await?;
        println!("商品已添加到购物车");
        
        // 返回首页
        browser.find_element("a#home").await?.click().await?;
        browser.wait_for_navigation().await?;
    }
    
    // 截图保存测试结果
    browser.screenshot("ecommerce_test.png").await?;
    println!("测试完成,截图已保存");
    
    Ok(())
}

许可证: MIT OR Apache-2.0


1 回复

Rust浏览器自动化插件库re_redap_browser使用指南

概述

re_redap_browser是一个Rust语言的浏览器自动化库,专门设计用于高效实现网页抓取和自动化测试任务。它提供了简洁的API来控制和操作浏览器,支持主流浏览器如Chrome、Firefox等。

主要特性

  • 支持无头(Headless)和有头浏览器模式
  • 提供DOM元素定位和操作功能
  • 支持表单填写和提交
  • 支持JavaScript执行
  • 支持页面截图和PDF生成
  • 支持网络请求拦截和修改
  • 轻量级且高性能

安装方法

在Cargo.toml中添加依赖:

[dependencies]
re_redap_browser = "0.3"

基本使用方法

1. 启动浏览器实例

use re_redap_browser::{Browser, BrowserOptions};

async fn start_browser() -> Result<(), Box<dyn std::error::Error>> {
    let options = BrowserOptions::default()
        .headless(true) // 无头模式
        .disable_images(true); // 禁用图片加载提升性能
    
    let browser = Browser::launch(options).await?;
    Ok(())
}

2. 打开页面并获取内容

use re_redap_browser::{Browser, Page};

async fn scrape_page() -> Result<(), Box<dyn std::error::Error>> {
    let browser = Browser::launch_default().await?;
    let page = browser.new_page().await?;
    
    // 导航到目标URL
    page.goto("https://example.com").await?;
    
    // 等待特定元素出现
    page.wait_for_selector("#main-content").await?;
    
    // 获取页面HTML
    let html = page.content().await?;
    println!("Page HTML: {}", html);
    
    Ok(())
}

3. 表单操作示例

async fn fill_form() -> Result<(), Box<dyn std::error::Error>> {
    let browser = Browser::launch_default().await?;
    let page = browser.new_page().await?;
    
    page.goto("https://example.com/login").await?;
    
    // 填写表单
    page.type_("#username", "my_username").await?;
    page.type_("#password", "secure_password").await?;
    
    // 点击提交按钮
    page.click("#submit-btn").await?;
    
    // 等待导航完成
    page.wait_for_navigation().await?;
    
    Ok(())
}

4. 截图功能

async fn take_screenshot() -> Result<(), Box<dyn std::error::Error>> {
    let browser = Browser::launch_default().await?;
    let page = browser.new_page().await?;
    
    page.goto("https://example.com").await?;
    
    // 全屏截图
    page.screenshot("screenshot.png", None).await?;
    
    // 元素截图
    page.screenshot_element("#featured-section", "element.png").await?;
    
    Ok(())
}

5. 执行JavaScript

async fn execute_js() -> Result<(), Box<dyn std::error::Error>> {
    let browser = Browser::launch_default().await?;
    let page = browser.new_page().await?;
    
    page.goto("https://example.com").await?;
    
    // 执行JavaScript并获取返回值
    let result: String = page.evaluate("document.title").await?;
    println!("Page title: {}", result);
    
    // 执行复杂JavaScript
    let sum: i32 = page.evaluate("1 + 2 + 3").await?;
    println!("Sum: {}", sum);
    
    Ok(())
}

高级用法

网络请求拦截

use re_redap_browser::{Request, Response};

async fn intercept_requests() -> Result<(), Box<dyn std::error::Error>> {
    let browser = Browser::launch_default().await?;
    let page = browser.new_page().await?;
    
    // 启用请求拦截
    page.en极request_interception(true).await?;
    
    // 设置请求拦截回调
    page.on_request(move |req: Request| {
        // 阻止所有图片请求
        if req.resource_type() == "image" {
            req.abort();
        } else {
            req.continue_();
        }
    }).await;
    
    page.goto("https://example.com").await?;
    
    Ok(())
}

并行处理多个页面

use futures::future::join_all;

async fn multiple_pages() -> Result<(), Box<dyn std::error::Error>> {
    let browser = Browser::launch_default().await?;
    
    let urls = vec![
        "https://example.com/page1",
        "https://example.com/page2",
        "https://example.com/page3",
    ];
    
    let tasks = urls.into_iter().map(|url| {
        let browser = browser.clone();
        async move {
            let page = browser.new_page().await?;
            page.goto(url).await?;
            let title = page.evaluate("document.title").await?;
            Ok::<_, Box<dyn std::error::Error>>(title)
        }
    });
    
    let results = join_all(tasks).await;
    
    for result in results {
        println!("Page title: {}", result?);
    }
    
    Ok(())
}

最佳实践

  1. 资源管理: 确保在使用完毕后关闭页面和浏览器实例
  2. 错误处理: 妥善处理网络超时和元素查找失败等情况
  3. 性能优化: 禁用不必要的资源加载(如图片、CSS)以提升速度
  4. 随机延迟: 在爬取时添加随机延迟避免被封锁
  5. 用户代理轮换: 定期更换User-Agent模拟不同设备

常见问题解决

  1. 元素查找失败: 确保使用正确的选择器,并添加足够的等待时间
  2. 内存泄漏: 定期重启浏览器实例,特别是在长时间运行的爬虫中
  3. 反爬机制: 考虑使用代理IP和更人性化的操作模式

完整示例Demo

下面是一个完整的网页抓取示例,结合了等待元素、获取内容和截图功能:

use re_redap_browser::{Browser, BrowserOptions};
use std::time::Duration;
use tokio::time::sleep;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 配置浏览器选项
    let options = BrowserOptions::default()
        .headless(true)
        .disable_images(true)
        .user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
    
    // 启动浏览器
    let browser = Browser::launch(options).await?;
    
    // 创建新页面
    let page = browser.new_page().await?;
    
    // 导航到目标网站
    page.goto("https://example.com").await?;
    
    // 等待主要内容加载
    page.wait_for_selector("#main-content").await?;
    
    // 随机延迟防止被屏蔽
    sleep(Duration::from_secs_f64(rand::random::<f64>() * 2.0)).await;
    
    // 获取页面标题
    let title: String = page.evaluate("document.title").await?;
    println!("页面标题: {}", title);
    
    // 获取特定元素文本
    let content: String = page.evaluate(
        "document.querySelector('#main-content').textContent"
    ).await?;
    println!("主要内容: {}", content);
    
    // 截图保存
    page.screenshot("example_screenshot.png", None).await?;
    
    // 关闭页面
    page.close().await?;
    
    // 关闭浏览器
    browser.close().await?;
    
    Ok(())
}

这个示例展示了:

  1. 浏览器配置和启动
  2. 页面导航和等待元素
  3. 添加随机延迟避免被检测
  4. 获取页面内容和执行JavaScript
  5. 截图功能
  6. 资源清理(关闭页面和浏览器)

您可以根据实际需求修改和扩展这个基础示例。

回到顶部