Rust浏览器自动化库chromiumoxide_pdl的使用,支持Chromium协议解析与自动化测试

Rust浏览器自动化库chromiumoxide_pdl的使用,支持Chromium协议解析与自动化测试

chromiumoxide 提供了一个高级异步API来控制 Chrome 或 Chromium 通过 DevTools 协议。它支持所有 Chrome DevTools 协议类型,可以启动无头(headless)或完整(非无头)的 Chrome/Chromium 实例,或连接到已运行的实例。

使用示例

use futures::StreamExt;
use chromiumoxide::browser::{Browser, BrowserConfig};

#[async_std::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 创建一个带有UI的浏览器实例 (默认是无头模式)
    let (mut browser, mut handler) =
        Browser::launch(BrowserConfig::builder().with_head().build()?).await?;
    
    // 创建一个持续处理handler的新任务
    let handle = async_std::task::spawn(async move {
        while let Some(h) = handler.next().await {
            if h.is_err() {
                break;
            }
        }
    });
    
    // 创建一个新页面并导航到URL
    let page = browser.new_page("https://en.wikipedia.org").await?;
    
    // 查找搜索框,输入搜索内容并回车
    page.find_element("input#searchInput")
           .await?
           .click()
           .await?
           .type_str("Rust programming language")
           .await?
           .press_key("Enter")
           .await?;

    let html = page.wait_for_navigation().await?.content().await?;
    
    browser.close().await?;
    handle.await;
    Ok(())
}

完整示例代码

下面是一个更完整的示例,展示了如何使用chromiumoxide_pdl进行Chromium协议解析和自动化测试:

use futures::StreamExt;
use chromiumoxide::browser::{Browser, BrowserConfig};
use chromiumoxide::page::Page;
use chromiumoxide::types::PrintToPdfParams;

#[async_std::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 配置浏览器选项
    let config = BrowserConfig::builder()
        .with_head() // 显示UI
        .with_timeout(std::time::Duration::from_secs(30))
        .build()?;
    
    // 启动浏览器
    let (mut browser, mut handler) = Browser::launch(config).await?;
    
    // 处理浏览器事件
    let handle = async_std::task::spawn(async move {
        while let Some(h) = handler.next().await {
            if h.is_err() {
                break;
            }
        }
    });
    
    // 创建新页面
    let page = browser.new_page("https://example.com").await?;
    
    // 等待页面加载完成
    page.wait_for_navigation().await?;
    
    // 截图
    let screenshot = page.screenshot().await?;
    std::fs::write("screenshot.png", screenshot)?;
    
    // 生成PDF
    let pdf_params = PrintToPdfParams::builder()
        .landscape(false)
        .display_header_footer(false)
        .print_background(true)
        .build();
    let pdf = page.pdf(pdf_params).await?;
    std::fs::write("page.pdf", pdf)?;
    
    // 执行自定义协议命令
    let title = page.title().await?;
    println!("Page title: {}", title);
    
    // 关闭浏览器
    browser.close().await?;
    handle.await;
    
    Ok(())
}

如何添加到项目

chromiumoxide支持async-std和tokio运行时。默认使用async-std。

使用async-std运行时:

chromiumoxide = { git = "https://github.com/mattsse/chromiumoxide", branch = "main"}

使用tokio运行时:

chromiumoxide = { git = "https://github.com/mattsse/chromiumoxide", features = ["tokio-runtime"], default-features = false, branch = "main"}

代码生成

chromiumoxide_pdl包含一个PDL解析器和一个将解析的PDL文件转换为Rust代码的生成器。chromiumoxide_cdp的唯一目的是在构建过程中调用生成器并包含生成的输出。

已知问题

  • 当手动关闭对实验性类型的支持时(export CDP_NO_EXPERIMENTAL=true),生成的Rust文件无法编译。

故障排除

Q: 新的chromium实例被启动但随后超时。 A: 检查你的chromium语言设置是否为英语。chromiumoxide尝试从chromium进程输出中解析调试端口,这仅限于英语。


1 回复

Rust浏览器自动化库chromiumoxide_pdl使用指南

chromiumoxide_pdl 是一个Rust库,用于Chromium协议解析和浏览器自动化测试。它提供了与Chromium浏览器交互的能力,支持自动化操作和协议级别的控制。

主要特性

  • Chromium DevTools Protocol (CDP) 解析
  • 浏览器自动化控制
  • 页面导航与操作
  • 元素查找与交互
  • 网络请求拦截与修改
  • JavaScript执行

安装

在Cargo.toml中添加依赖:

[dependencies]
chromiumoxide_pdl = "0.5"
tokio = { version = "1.0", features = ["full"] }
futures = "0.3"

完整示例代码

下面是一个完整的浏览器自动化示例,结合了内容中提供的各个功能点:

use chromiumoxide_pdl::{
    browser::{Browser, BrowserConfig},
    cdp::{
        browser_protocol::network::{RequestPattern, EventRequestWillBeSent},
        browser_protocol::performance::{EnableParams, Metric}
    }
};
use futures::{StreamExt, FutureExt};
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 配置并启动浏览器
    let config = BrowserConfig::builder()
        .headless(true)  // 无头模式
        .timeout(Duration::from_secs(30))  // 设置超时时间
        .build()?;
    
    let (mut browser, mut handler) = Browser::launch(config).await?;
    
    // 处理浏览器事件的异步任务
    let browser_task = tokio::task::spawn(async move {
        while let Some(h) = handler.next().await {
            if h.is_err() {
                break;
            }
        }
    });

    // 2. 创建新页面并导航
    let page = browser.new_page("about:blank").await?;
    
    // 3. 设置网络请求拦截
    let patterns = vec![
        RequestPattern {
            url_pattern: Some("*.png".to_string()),
            resource_type: None,
            interception_stage: None,
        }
    ];
    page.set_request_interception(patterns).await?;
    
    // 启动拦截请求处理任务
    let mut events = page.event_listener::<EventRequestWillBeSent>().await?;
    let intercept_task = tokio::spawn(async move {
        while let Some(event) = events.next().await {
            let request = event.request;
            println!("拦截到请求: {}", request.url);
            // 这里可以添加请求处理逻辑
        }
    });

    // 导航到目标网站
    page.goto("https://www.rust-lang.org").await?;
    page.wait_for_navigation().await?;

    // 4. 页面元素操作
    // 查找并点击"Learn"链接
    if let Some(button) = page.find_element("a[href='/learn']").await? {
        button.click().await?;
        page.wait_for_navigation().await?;
    }

    // 在搜索框中输入并搜索
    if let Some(search) = page.find_element("input[type='search']").await? {
        search.type_str("Rust book").await?;
        search.press_key("Enter").await?;
        page.wait_for_navigation().await?;
    }

    // 5. 执行JavaScript
    // 获取页面标题
    let title: String = page.evaluate("document.title").await?;
    println!("当前页面标题: {}", title);

    // 修改页面背景色
    page.evaluate("document.body.style.backgroundColor = 'lightblue'").await?;

    // 6. 性能监控
    // 启用性能指标收集
    page.execute(EnableParams::default()).await?;
    
    // 获取性能指标
    let metrics: Vec<Metric> = page.evaluate("window.performance.getEntries()").await?;
    println!("性能指标:");
    for metric in metrics {
        println!("{}: {}", metric.name, metric.value);
    }

    // 7. 自定义协议解析示例
    use chromiumoxide_pdl::pdl::Parser;
    
    let pdl = r#"
    domain MyDomain
        version 1.0

        type MyType extends object
            properties
                string name
                integer id
    "#;

    let parser = Parser::new();
    let protocol = parser.parse(pdl)?;
    println!("解析的自定义协议类型: {:?}", protocol.types);

    // 清理工作
    intercept_task.abort();
    browser.close().await?;
    browser_task.await?;
    
    Ok(())
}

代码说明

  1. 浏览器启动:配置无头浏览器并启动,设置超时时间防止长时间等待。

  2. 页面导航:创建新页面并导航到目标URL,等待页面完全加载。

  3. 网络拦截:设置拦截规则,捕获所有PNG图片请求并打印URL。

  4. 元素操作

    • 查找并点击页面上的特定元素
    • 在输入框中输入文本并模拟回车键
  5. JavaScript执行

    • 获取页面标题
    • 修改页面样式
  6. 性能监控:收集并打印页面性能指标。

  7. 自定义协议解析:演示如何使用PDL解析自定义协议。

注意事项

  1. 确保系统中已安装Chromium或Chrome浏览器
  2. 适当添加等待时间处理页面加载延迟
  3. 网络拦截会增加请求处理开销
  4. 资源使用完毕后要正确关闭和清理

这个完整示例展示了chromiumoxide_pdl库的主要功能,可以根据实际需求进行修改和扩展。

回到顶部