You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust实现浏览器请求拦截遇阻,求解决方案(基于headless_chrome)

捕获无头浏览器请求的解决方案

问题背景

需要捕获并打印浏览器发出的每一个请求,使用headless_chrome crate时遇到困难:不知道如何创建Arc<dyn RequestInterceptor + Send + Sync>实例,也不清楚如何正确处理请求并返回RequestPausedDecision。

原始尝试代码

use std::sync::Arc;

use anyhow::Result;
use headless_chrome::browser::tab::RequestInterceptor;
use headless_chrome::browser::tab::Tab;
use headless_chrome::protocol::cdp::types::Event;
use headless_chrome::protocol::cdp::IndexedDB::RequestData;
use headless_chrome::protocol::cdp::Page;
use headless_chrome::Browser;

#[tokio::main]
async fn request_interceptor_function(mut url: String) -> Result<(), Box<dyn Error>> {
    let browser = Browser::default()?;

    let tab = browser.new_tab()?;

    tab.navigate_to(
        "https://animeheaven.ru/watch/the-ancient-magus-bride-season-2.55921?ep=183710",
    )?;
    println!("Navigated to website");
    // Arc<Transport>, SessionId, RequestPausedEvent
    const req_interceptor: Arc<dyn RequestInterceptor + Send + Sync> = Arc::new(
        |transport: Arc<transport::Transport>,
         session_id: SessionId,
         intercepted_req: RequestPausedEvent| {

        },
    );
    Ok(())
}


fn main() {
    let url = "https://www.example.com";
    request_interceptor_function(title.to_string());
}

修正后的可行代码

use anyhow::Result;
use headless_chrome::browser::tab::{RequestInterceptor, RequestPausedDecision};
use headless_chrome::browser::transport::{SessionId, Transport};
use headless_chrome::protocol::cdp::Fetch::events::RequestPausedEvent;
use headless_chrome::Browser;
use std::error::Error;
use std::sync::Arc;
use tokio;

struct PrintingInterceptor {}

impl RequestInterceptor for PrintingInterceptor {
    fn intercept(
        &self,
        _transport: Arc<Transport>,
        _session_id: SessionId,
        event: RequestPausedEvent,
    ) -> RequestPausedDecision {
        // 打印捕获到的请求URL
        let url = event.params.request.url.as_str();
        println!("捕获到请求: {}", url);
        // 允许请求继续执行
        RequestPausedDecision::Continue(None)
    }
}

#[tokio::main]
async fn request_interceptor_function(url: &str) -> Result<(), Box<dyn Error>> {
    println!("正在启动浏览器...");
    let browser = Browser::default()?;
    let tab = browser.new_tab()?;

    // 创建拦截器实例并启用请求拦截
    let request_interceptor: Arc<dyn RequestInterceptor + Send + Sync> =
        Arc::new(PrintingInterceptor {});
    tab.enable_request_interception(request_interceptor)?;
    println!("已启用请求拦截");

    // 导航到目标页面
    tab.navigate_to(url)?;
    tab.wait_until_navigated()?;
    println!("已导航到目标页面");

    // 等待一段时间以捕获后续异步请求(按需调整时长)
    tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;

    Ok(())
}

fn main() -> Result<(), Box<dyn Error>> {
    let url = "https://animeheaven.ru/watch/the-ancient-magus-bride-season-2.55921?ep=183710";
    // 阻塞执行异步函数
    tokio::runtime::Runtime::new()?.block_on(request_interceptor_function(url))
}

关键修正点

  1. 拦截器实现:通过自定义结构体PrintingInterceptor实现RequestInterceptor trait,在intercept方法中处理请求(打印URL)并返回RequestPausedDecision::Continue(None)允许请求继续。
  2. 拦截启用时机:必须在调用navigate_to之前启用请求拦截,否则无法捕获页面加载过程中的请求。
  3. 异步处理修正:原始代码中main函数直接调用异步函数会返回未执行的Future,修正后使用Tokio Runtime阻塞执行异步逻辑,确保代码完整运行。
  4. 等待异步请求:添加sleep等待页面加载后的异步请求(比如Ajax、媒体资源请求),避免程序过早退出导致部分请求未被捕获。

其他可选方案

除了headless_chrome,还可以使用以下Rust crate实现类似功能:

  • chromiumoxide:基于Chrome DevTools Protocol的现代无头浏览器库,API设计更简洁,支持请求拦截。
  • fantoccini:WebDriver协议的客户端库,可配合浏览器驱动使用,支持通过配置或代理实现请求捕获。

内容的提问来源于stack exchange,提问作者Daniel Vaško

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 14:05:40