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)) }
关键修正点
- 拦截器实现:通过自定义结构体
PrintingInterceptor实现RequestInterceptortrait,在intercept方法中处理请求(打印URL)并返回RequestPausedDecision::Continue(None)允许请求继续。 - 拦截启用时机:必须在调用
navigate_to之前启用请求拦截,否则无法捕获页面加载过程中的请求。 - 异步处理修正:原始代码中
main函数直接调用异步函数会返回未执行的Future,修正后使用Tokio Runtime阻塞执行异步逻辑,确保代码完整运行。 - 等待异步请求:添加
sleep等待页面加载后的异步请求(比如Ajax、媒体资源请求),避免程序过早退出导致部分请求未被捕获。
其他可选方案
除了headless_chrome,还可以使用以下Rust crate实现类似功能:
- chromiumoxide:基于Chrome DevTools Protocol的现代无头浏览器库,API设计更简洁,支持请求拦截。
- fantoccini:WebDriver协议的客户端库,可配合浏览器驱动使用,支持通过配置或代理实现请求捕获。
内容的提问来源于stack exchange,提问作者Daniel Vaško
相关产品推荐
相关产品推荐

