rpage 1.0.3

Rust browser automation (DrissionPage-inspired) with built-in AI agent diagnostics — page_snapshot/smart_click/eval_agent/page_diagnostics
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
# rpage 🦀🌐


> Rust 版 DrissionPage — 浏览器自动化 + HTTP 会话 + Cookie 互通,三合一。**580+ 公开方法,12,000+ 行 Rust**。内置 AI Agent 诊断接口(`page_snapshot` / `smart_click` / `eval_agent` / `page_diagnostics`)。

`rpage` 是一个受 [DrissionPage](https://github.com/g1879/DrissionPage) 启发的 Rust 浏览器自动化库。

## ✨ 核心特性


- **一个函数启动**`WebPage::new()` 自动检测 Chrome → 启动子进程 → CDP 连接
- **零自动化标记** — 不传 `--enable-automation`,永不触发验证码
- **智能标签接管**`connect()` 自动选择当前激活标签页,不会误开新标签
- **自动反检测** — stealth 脚本自动注入
- **Cookie 互通** — 浏览器 ↔ HTTP 会话共享 Cookie,支持导入/导出文件
- **智能等待**`get()` 等加载,`ele()`/`eles()` 自动重试,超时可配置
- **中文完美**`fill()` 用 JS `nativeInputValueSetter`
- **鲁棒交互**`click()` 自动 fallback CDP→JS,拖拽到元素或坐标
- **链式调用**`page.goto(url).await?.type_text("#kw", "rust").await?` 一行完成导航+输入
- **一步到位 API**`click_ele()`/`get_text()`/`get_attr()` 无需先 `ele()` 再操作
- **AI Agent 接口**`page_snapshot()` 给 LLM 结构化页面快照;`smart_click()`/`smart_fill()` 自然语言定位;`eval_agent()` 执行 JS 并捕获新增异常;`page_diagnostics()` 一次性聚合 JS 异常 + 错误日志 + 失败请求 + 加载时序(专为 LLM 调试前端设计)
- **网络包实时监听**`on_request()`/`on_response()` 回调式捕获每个请求和响应
- **网络监听模式** — listen_start/stop + continue_request/fail_request 请求级控制
- **设备模拟** — 设备像素比/触摸模式/地理位置+刷新
- **资源分析** — links/images/ele_count 一键提取页面资源
- **网络控制** — URL 拦截/离线模式/清除缓存/禁用图片
- **标签页增强** — tab_to_front/get_tab_by_title/get_tab_by_url/wait_new_tab
- **Tab 管理** — 创建/切换/关闭/列表
- **条件等待** — 等元素出现/消失/删除,等标题/URL 变化,等 JS 表达式
- **Element 等待** — wait_for_visible/hidden/stale/clickable/enabled/text/attribute
- **运行时修改** — headers/user_agent/viewport
- **窗口管理** — maximize/minimize/fullscreen/restore/set_size
- **加载策略** — normal/eager/none 三种页面加载模式
- **事件回调** — on_dialog/on_load/on_close 事件监听
- **批量操作**`eles().texts()` 一行获取所有文本
- **文件上传** — 浏览器 + Session multipart 双模式
- **PDF/截图** — 页面级和元素级
- **下载管理** — CDP 下载事件监听 + 等待下载完成
- **网络拦截** — Fetch.enable 拦截/修改/阻止请求
- **ActionChain** — 复杂鼠标键盘序列
- **iframe 上下文** — 进入 iframe 执行操作
- **网络监控** — 记录所有请求/响应/失败
- **Console 捕获** — 拦截 console.log/warn/error
- **WebSocket 监听** — 监听 WebSocket 帧
- **性能指标** — 页面计时 + JS Heap 等运行时指标
- **Init Script** — 页面加载前注入 JS
- **CSS 注入** — 动态注入/移除 CSS 样式
- **灵活配置** — 环境变量 `RPAGE_CHROME_PATH`,PATH 搜索,标准路径
- **同步 API**`SyncPage` 零 await 封装,`SyncPage::connect()` 一步到位,自动接管当前激活标签页
- **Agent 智能接口**`interactive_elements()`/`page_snapshot()`/`smart_click()`/`smart_fill()` 直接给 AI Agent 用
- **JS XPath 回退** — 非 CSS 定位器(`text:`/`tag:`)自动回退 XPath

## 🚀 快速开始


```rust
use rpage::prelude::*;

#[tokio::main]

async fn main() -> rpage::Result<()> {
    let page = WebPage::new().await?;           // 一行启动 Chrome
    page.get("https://www.baidu.com").await?;   // 自动等待加载
    page.ele("#kw").await?.fill("rust教程").await?;  // 中文输入
    page.ele("#su").await?.click().await?;       // 搜索
    let results = page.eles("h3").await?;       // 自动重试等待
    for (i, text) in results.texts().iter().enumerate() {
        println!("{}. {}", i + 1, text);
    }
    Ok(())
}
```

### 链式调用 — 一行完成复杂操作


```rust
// 链式:导航 → 输入 → 点击,一步到位
page.goto("https://www.baidu.com").await?
    .type_text("#kw", "rust教程").await?
    .click_ele("#su").await?;
```

### 同步 API — 零 await,零 tokio


`SyncPage` 将全部 async API 封装为同步调用,无需 `#[tokio::main]`:

```rust
use rpage::sync::SyncPage;

fn main() -> rpage::Result<()> {
    let p = SyncPage::connect("http://127.0.0.1:9222")?;  // 自动接管当前激活标签页

    p.get("https://httpbin.org/forms/post")?;
    p.type_text("input[name='custname']", "张三")?;
    p.click_ele("input[value='medium']")?;
    p.screenshot("form.png")?;

    let title = p.title()?;
    let cookies = p.cookies()?;
    let links = p.links()?;
    println!("title={}, {} cookies, {} links", title, cookies.len(), links.len());
    Ok(())
}
```

### Agent 智能接口 — 为 AI Agent 设计


```rust
// 1. 分析页面交互元素
let elements = p.interactive_elements()?;
for el in &elements {
    println!("{:?} {} type={:?}", el.tag, el.text, el.input_type);
}

// 2. 页面快照(给 LLM 上下文)
let snap = p.page_snapshot()?;
// snap.url, snap.title, snap.viewport_size, snap.interactive_elements, snap.visible_text

// 3. 智能操作 — 用自然语言描述即可
let result = p.smart_click("提交");
let result = p.smart_fill("用户名", "agent_bot");

// 4. DOM 快照(结构化 JSON)
let dom = p.dom_snapshot()?;

// 5. 性能指标
let metrics = p.performance_metrics()?;
```

### 能力展示


运行 `cargo run --example showcase` 查看 **10 大场景 50+ 项操作** 的完整演示:

```
 1. 页面导航 & DOM 操作     — 导航、表单填写、复选框/单选框、截图
 2. JavaScript 执行         — execute、run_async_js、run_js_with_args、全局注入
 3. 元素高级操作            — DOM 树遍历、属性/样式操作、拖拽
 4. 多标签页管理            — new_tab、switch_to_tab、跨标签导航
 5. Cookie 管理             — 读取、设置、删除、跨请求验证
 6. 网络控制                — UA伪装、自定义Headers、URL屏蔽
 7. 截图 & PDF              — 全页截图、元素截图、PDF生成
 8. 智能等待                — wait_ele、wait_js、wait_url_contains
 9. 设备模拟 & 视口         — viewport、device_scale、touch、geolocation、timezone
10. Agent 智能接口          — interactive_elements、page_snapshot、smart_click/fill
```

## 📦 安装

```toml
[dependencies]
rpage = "0.1"
```

## 📖 API 参考 (568 方法)


### 链式便捷 API (8)


无需先 `ele()` 再操作,一步到位。所有方法返回 `&Self`,支持链式调用。

```rust
page.goto(url).await?;                       // 导航(返回 &Self)
page.type_text("#kw", "rust教程").await?;    // 定位+清空+输入
page.click_ele("#btn").await?;               // 定位+点击
page.get_text("h1").await?;                  // 定位+获取文本
page.get_attr("#link", "href").await?;       // 定位+获取属性
page.input_text("#input", "追加文本").await?; // 定位+追加输入
page.hover_ele("#menu").await?;              // 定位+悬停
page.scroll_to_ele("#section").await?;       // 定位+滚动到元素

// 链式组合示例
page.goto("https://example.com").await?
    .type_text("#search", "query").await?
    .click_ele("#submit").await?;
```

### 快速查询 (3)


```rust
let exists = page.exists("#result").await?;     // bool — 元素是否存在
let n = page.count("li.item").await?;           // usize — 匹配数量
let el = page.ele_or_none("#opt").await?;       // Option<Element> — 无则 None
```

### DrissionPage 别名 (3)


兼容 DrissionPage 命名习惯:

```rust
let url = page.current_url().await?;    // 等同 page.url()
let title = page.current_title().await?; // 等同 page.title()
let src = page.page_source().await?;    // 等同 page.html()
```

### 页面导航 + 信息 (9)


```rust
page.get(url).await?;           // 自动等 DOMContentLoaded
page.refresh().await?;          // 智能等待
page.back().await?;
page.forward().await?;
let title = page.title().await?;
let url = page.url().await?;
let html = page.html().await?;
let val = page.execute("1+1").await?;
page.evaluate_on_new_document("...").await?;
```

### 元素定位 — 自动重试 (2)


```rust
let el = page.ele("#id").await?;
let els = page.eles("h3").await?;
```

| 语法 | 说明 |
|------|------|
| `#id`, `.class` | CSS |
| `@class=btn` | 属性精确 |
| `@class*=btn` | 属性包含 |
| `@class^=btn` | 属性前缀 |
| `@class$=btn` | 属性后缀 |
| `text:登录` | 文本精确 |
| `text*:登录` | 文本包含 |
| `tag:form@@text:登录` | 链式定位 |

### 条件等待 (10)


```rust
let el = page.wait_ele("#result", 10).await?;
page.wait_ele_hidden("#loading", 5).await?;
page.wait_ele_deleted(".modal", 5).await?;
page.wait_title_contains("搜索结果", 5).await?;
page.wait_url_contains("search", 5).await?;
page.wait_js("document.querySelectorAll('.item').length > 5", 10).await?;
let dl = page.wait_download(30).await?;
// ── 精确匹配等待 ──
page.wait_url_is("https://example.com/done", 10).await?;
page.wait_title_is("完成", 10).await?;
page.wait_for_navigation(10).await?;
```

### 标签页 (10)


```rust
page.new_tab().await?;
let titles = page.tab_titles().await?;
let urls = page.tab_urls().await?;
page.switch_to_tab(1).await?;
page.close_tab(0).await?;
let tabs = page.tabs().await?;
// ── iter10 增强 ──
page.tab_to_front(0).await?;           // 将标签页置顶
let idx = page.get_tab_by_title("百度").await?;  // 按标题查找
let idx = page.get_tab_by_url("example").await?; // 按 URL 查找
page.wait_new_tab(5).await?;           // 等待新标签页
page.set_download_file_name("report.pdf").await?; // 设置下载文件名
```

### 元素操作 (55+ 方法)


```rust
// ── 基础交互 ──
el.click().await?;              // CDP → JS 自动 fallback
el.fill("rust教程").await?;    // 清空+输入
el.input("追加").await?;
el.clear().await?;
el.hover().await?;
el.submit().await?;
el.right_click().await?;
el.double_click().await?;
el.press_key("Enter").await?;

// ── 拖拽 ──
el.drag_to(&target).await?;     // 拖到另一个元素
el.drag_to_offset(100.0, 50.0).await?;  // 拖到相对坐标

// ── 下拉框 / 文件 ──
el.select("选项").await?;
el.select_by_value("val").await?;
el.upload_file("/path/to/file").await?;
el.upload_files(&["/a", "/b"]).await?;

// ── 复选框 ──
el.check().await?;
el.uncheck().await?;
let checked = el.checked();

// ── 截图 ──
el.screenshot("el.png").await?;
let bytes = el.screenshot_bytes().await?;

// ── 属性 / 状态 ──
let v = el.attr("href");           // Option<&str>
let v = el.value().await?;
let (x,y,w,h) = el.rect().await?;
let bbox = el.bounding_box().await?;  // CDP + JS fallback
let s = el.style("color").await?;
el.set_attr("class", "active").await?;
el.is_displayed();                  // 同步
el.is_visible().await?;            // 异步,CSS+几何双重检测
el.is_enabled();
el.is_selected().await?;

// ── 相对定位 ──
let p = el.parent().await?;
let c = el.first_child().await?;
let n = el.next().await?;
let pv = el.prev().await?;
let child = el.ele("a")?;
let children = el.eles("li")?;
let children = el.children()?;
let sib = el.sibling()?;
let inner = el.inner_html()?;
let outer = el.outer_html()?;

// ── 焦点 / 选择 ──
el.focus().await?;
el.blur().await?;
el.select_text().await?;
el.scroll_into_view().await?;
el.scroll_to_top().await?;

// ── Shadow DOM ──
let shadow = el.shadow_ele("div").await?;
let shadows = el.shadow_eles("li").await?;

// ── JS ──
el.js("this.style.color='red'").await?;
```

### Element 等待方法 (40+)


```rust
// ── 可见性 ──
el.wait_for_visible().await?;
el.wait_for_visible_with_timeout(Duration::from_secs(10)).await?;
el.wait_for_hidden().await?;
el.wait_for_hidden_with_timeout(Duration::from_secs(5)).await?;

// ── 状态 ──
el.wait_for_enabled().await?;
el.wait_for_clickable().await?;
el.wait_for_stale().await?;

// ── 文本 ──
el.wait_for_text("加载完成").await?;
el.wait_for_text_eq("精确匹配").await?;
el.wait_for_text_contains("部分").await?;

// ── 属性 ──
el.wait_for_attribute("class", "active").await?;
el.wait_for_attribute_contains("class", "act").await?;

// ── 完全自定义 ──
let opts = WaitOptions::new(Duration::from_secs(30), Duration::from_millis(200));
el.wait_for_visible_with_options(opts).await?;
```

### 批量操作 — ElementBatch


```rust
let els = page.eles("h3").await?;
let texts = els.texts();                // Vec<&str>
let hrefs = els.attr_values("href");    // Vec<Option<&str>>
let visible = els.displayed();          // Vec<&Element>
```

### 页面操作 (20+)


```rust
page.scroll_to(0, 500).await?;
page.scroll_by(0, 300).await?;          // 相对滚动
page.scroll_to_top().await?;
page.scroll_to_bottom().await?;
page.screenshot("shot.png").await?;
page.pdf("page.pdf").await?;
page.press("Enter").await?;
page.set_viewport(1920, 1080).await?;
page.handle_alert(true, None).await?;
page.frame_html("iframe").await?;
page.frame_execute("iframe", "document.title").await?;
page.scroll_to_element(&el).await?;
page.run_async_js("await fetch('/api')").await?;
page.keys("hello world").await?;        // 逐字符输入(支持中文)
page.refresh_ele(&el).await?;           // 重新定位元素
```

### 窗口管理 (7)


```rust
page.maximize().await?;
page.minimize().await?;
page.fullscreen().await?;
page.restore().await?;
page.set_window_size(1280, 800).await?;
let (l, t, w, h) = page.get_window_bounds().await?;
```

### 加载策略


```rust
page.set_load_strategy("eager").await?;  // normal / eager / none
let strategy = page.load_strategy();      // &str
```

### 事件回调 (3)


```rust
page.on_dialog(|msg, r#type| {
    println!("Dialog: {} ({})", msg, r#type);
    true  // accept
}).await?;

page.on_load(|url| {
    println!("Page loaded: {}", url);
}).await?;

page.on_close(|| {
    println!("Page closed");
}).await?;
```

### Cookie (10)


```rust
let cookies = page.cookies().await?;
page.set_cookie(cookie).await?;
page.delete_cookie("name").await?;
page.clear_cookies().await?;
page.sync_cookies().await?;
page.save_cookies_to_file("cookies.json").await?;
page.load_cookies_from_file("cookies.json").await?;
```

### 运行时修改 (3)


```rust
page.set_extra_headers(headers).await?;
page.set_user_agent("Mozilla/5.0 ...").await?;
page.set_viewport(1920, 1080).await?;
```

### Session HTTP (7)


```rust
let resp = page.session_get(url).await?;
let resp = page.session_post(url, body).await?;
let resp = page.session_put(url, body).await?;
let resp = page.session_delete(url).await?;
let resp = page.session_head(url).await?;
let resp = page.session_patch(url, body).await?;
let resp = page.session_post_json(url, &data).await?;  // JSON body
```

此外还有:

```rust
page.post(url, body).await?;
page.post_multipart(url, fields, "file", "/path").await?;
page.post_json(url, data).await?;
page.session_download(url, "file.zip").await?;
let status = page.session_status(url).await?;
```

### 网络包实时监听 (3)


回调式捕获浏览器每个请求和响应:

```rust
// 监听请求
page.on_request(|req| {
    println!("→ {} {}", req.method, req.url);
}).await?;

// 监听响应
page.on_response(|resp| {
    println!("← {} {}", resp.status, resp.url);
}).await?;

// 清除所有监听器
page.clear_listeners().await?;
```

### Console 捕获 (3)


```rust
page.execute("console.log('hello')").await?;
let logs = page.console_log();     // Vec<ConsoleMessage>
page.clear_console();
```

### Init Script + CSS 注入 (4)


```rust
let id = page.add_init_script("my", "window.test = 42").await?;
page.remove_init_script(&id).await?;

let css_id = page.inject_css("body { background: red }").await?;
page.remove_css(&css_id).await?;
```

### 性能指标 (3)


```rust
let timing = page.page_timing().await?;     // HashMap<String, f64>
let metrics = page.performance_metrics().await?;  // Vec<(String, f64)>
let snapshot = page.dom_snapshot().await?;   // serde_json::Value
```

### 下载管理 (4)


```rust
let downloads = page.downloads();           // 获取所有下载
let dl = page.wait_download(30).await?;    // 等待最近下载完成
println!("{:?}", dl.save_path);             // 下载路径
page.download_manager().completed();        // 已完成的下载
```

### 网络拦截 (3)


```rust
let guard = page.enable_intercept("*/api/*").await?;
tokio::time::sleep(Duration::from_secs(5)).await;
for req in guard.paused_requests() {
    guard.continue_request(&req.request_id, None).await?;
}
guard.disable().await?;  // 或 drop(guard) 自动关闭
```

### ActionChain — 复杂操作序列 (8)


```rust
page.actions()
    .move_to(100.0, 200.0)
    .click_at(100.0, 200.0)
    .double_click_at(150.0, 200.0)
    .right_click_at(200.0, 200.0)
    .key_down("Control")
    .press("a")
    .key_up("Control")
    .pause(Duration::from_millis(500))
    .perform()
    .await?;
```

### iframe 上下文 (4)


```rust
let ctx = page.enter_frame("iframe").await?;
ctx.execute("document.title").await?;
let el = ctx.ele("#btn").await?;
let html = ctx.html().await?;
```

### 网络监控 (5)


```rust
page.network_monitor().requests();          // 所有请求
page.network_monitor().responses();         // 所有响应
page.network_monitor().failures();          // 失败请求
page.network_monitor().find_requests_by_url("api");
page.network_monitor().clear();
```

### WebSocket 监听 (2)


```rust
page.listen_websocket().await?;
let frames = page.websocket_frames();
```

### 网络监听模式 (4) — iter10


```rust
page.listen_start().await?;                              // 开启网络监听
// ... 用户操作 ...
let reqs = page.network_monitor().requests();            // 获取捕获的请求
page.listen_stop().await?;                               // 停止监听
page.continue_request("req_id", None).await?;            // 继续请求
page.continue_request("req_id", Some("https://new.url")).await?; // 重定向
page.fail_request("req_id").await?;                      // 拒绝请求
```

### 设备模拟 + 网络控制 (9) — iter10


```rust
page.set_device_scale(2.0).await?;                       // 设置设备像素比
page.set_touch(true).await?;                             // 开启触摸模式
page.set_location_and_reload(39.9, 116.4).await?;       // 地理位置+刷新
page.smooth_scroll(0, 1500, 500).await?;                 // 平滑滚动(x, y, ms)
page.set_blocked_urls(&["*://*/*/*.css"]).await?;        // URL 拦截
page.set_offline(true).await?;                           // 离线模式
page.clear_cache().await?;                               // 清除缓存
page.disable_images().await?;                            // 禁用所有图片
page.get_and_wait(url, 10).await?;                       // 导航+等待标题
```

### 资源分析 (3) — iter10


```rust
let links = page.links().await?;                         // Vec<String> 所有链接
let imgs = page.images().await?;                         // Vec<String> 所有图片
let n = page.ele_count("a").await?;                      // 匹配元素数量
```

### 模式切换 + 生命周期


```rust
page.to_session().await?;    // 浏览器 → HTTP
page.to_chromium().await?;   // HTTP → 浏览器
page.sleep(Duration::from_secs(1)).await;
page.close().await?;
page.quit().await?;
```

### 自定义配置


```rust
let opts = WebPageOptions {
    chromium: ChromiumOptions {
        headless: true,
        timeout: Duration::from_secs(10),  // 自定义超时
        proxy: Some("http://proxy:8080".into()),
        user_agent: "Mozilla/5.0 ...".into(),
        browser_path: Some("/usr/bin/chromium".into()),
        disable_gpu: true,
        no_sandbox: true,
        extension_dirs: vec!["/path/to/ext".into()],
        ..Default::default()
    },
    ..Default::default()
};
let page = WebPage::with_options(opts).await?;
```

环境变量:`RPAGE_CHROME_PATH` 指定 Chrome 路径

### 低级访问


```rust
page.is_chromium();       // bool
page.is_session();        // bool
page.inner_page();        // Option<&Page>
page.options();           // Option<&ChromiumOptions>
```

## 项目结构


```
rpage/  (12,000+ 行 Rust, 580+ 方法)
├── src/
│   ├── chromium_page.rs  # CDP 浏览器控制 (190+ 方法) + Agent 接口
│   ├── element.rs        # 元素操作 (100+ 方法 + ElementBatch + Wait)
│   ├── sync.rs           # SyncPage 同步封装 (100+ 方法)
│   ├── agent.rs          # Agent 数据结构 (InteractiveElement/PageSnapshot/ActionAttempt)
│   ├── js_helpers.rs     # JS 代码片段 (XPath 回退/DOM 遍历等)
│   ├── web_page.rs       # 统一双模式页 (120+ 方法)
│   ├── session_page.rs   # HTTP 会话 (25+ 方法)
│   ├── download.rs       # 下载管理 (13 方法)
│   ├── network.rs        # 网络监控 + 实时监听 + 监听模式 (20 方法)
│   ├── locator.rs        # 定位器解析 + XPath 回退 (6 方法)
│   ├── config.rs         # 配置 (24 方法)
│   ├── stealth.rs        # 反检测 (5 方法)
│   ├── cookie-hub.rs     # Cookie 同步 + 文件 (10 方法)
│   ├── wait.rs           # 等待策略 (6 方法)
│   ├── console.rs        # Console 捕获 (5 方法)
│   ├── websocket.rs      # WebSocket 监听 (5 方法)
│   ├── error.rs          # 错误类型
│   ├── prelude.rs        # 预导入
│   └── lib.rs            # 入口
├── examples/
│   └── showcase.rs       # 能力展示:10 大场景 50+ 项操作
└── tests/                # 145 个测试
```

## 更新日志


### 1.0.3


- **文档更新**:README 补充 AI Agent 诊断接口的特性说明与 1.0.1/1.0.2 更新日志;Cargo.toml description 更新以反映 agent 能力。

### 1.0.2


- **类型序列化补全**:`CookieInfo``DownloadInfo``DownloadStatus``Serialize`/`Deserialize`,使诊断/下载数据可直接序列化给 LLM。

### 1.0.1


- **新增 AI Agent 诊断接口**(`agent.rs` + `chromium_page.rs`):
  - `PageDiagnostics` — 页面诊断快照,一次性聚合 JS 异常(含文件名/行号/调用栈)、Error/Warn 日志、失败网络请求、加载时序。`has_errors` 字段快速判断页面健康。
  - `EvalResult` — JS 执行结果 + 执行期间新增的异常,构成"注入→诊断"闭环。
- **新增方法**(`ChromiumPage` / `WebPage` / `SyncPage` 三处统一):
  - `eval_agent(js)` — 执行 JS,只回报本次执行**新增**的异常(不混入历史噪音)。
  - `page_diagnostics()` — 页面健康报告(过滤掉 log/info/debug,只保留 Error/Warn 省 token)。
  - `clear_diagnostics()` — 清空控制台 + 网络记录,操作前清零确保后续诊断干净。
- **底层类型补序列化**:`ConsoleEntry``ConsoleLevel``JsException``RequestRecord``ResponseRecord``FailedRequest``RequestInfo``ResponseInfo``WsFrame``WsEvent` 全部补 `Serialize`/`Deserialize`- **根级 re-export**:`ActionAttempt``EvalResult``PageDiagnostics``PageSnapshot``PageSummary` 可直接 `rpage::X` 访问。

## License


MIT