# rpage đĻđ
> A Rust browser-automation library inspired by [DrissionPage](https://github.com/g1879/DrissionPage) â CDP browser control + HTTP session + shared cookies, in one crate.
`rpage` drives a real Chrome/Chromium over the DevTools Protocol *and* speaks
plain HTTP (reqwest) in the same API, with cookies shared between the two. It
aims for the ergonomics of DrissionPage with parity-or-better coverage of
Playwright's most useful features (response mocking, semantic locators,
actionability waits).
```toml
[dependencies]
rpage = "1"
```
## Why rpage
- **One call to start** â `WebPage::new()` detects Chrome, launches it, connects over CDP.
- **No automation fingerprint** â never passes `--enable-automation`; behaves like a hand-opened browser.
- **Dual mode** â browser (CDP) and HTTP session in one API, with cookie sync and `to_session()`/`to_chromium()` switching.
- **Smart waiting** â `get()` waits for load; `ele()`/`eles()` auto-retry; click waits for actionability.
- **Sync *and* async** â full async API, plus a zero-`await` `SyncPage` wrapper.
- **Unicode-perfect input** â `fill()` types Chinese/any Unicode via CDP `insertText`.
- **Rich locators** â CSS, XPath, text/attr operators (`=` `:` `^` `$`), same-element `@@`/`@|`, chains.
- **Network superpowers** â capture request/response bodies, mock responses (`route.fulfill`), intercept/redirect/block, raw CDP passthrough.
## Quick start
```rust
use rpage::prelude::*;
#[tokio::main]
async fn main() -> rpage::Result<()> {
let page = WebPage::new().await?; // launch Chrome
page.get("https://example.com").await?; // navigate (auto-waits)
page.ele("#search").await?.fill("rust æį¨").await?; // type (Unicode OK)
page.ele("#submit").await?.click().await?; // waits for actionability
for text in page.eles("h3").await?.texts() { // auto-retry locate
println!("{text}");
}
Ok(())
}
```
### Chaining
```rust
page.goto("https://example.com").await?
.type_text("#search", "query").await?
.click_ele("#submit").await?;
```
### Sync API â no `await`, no `#[tokio::main]`
```rust
use rpage::sync::SyncPage;
fn main() -> rpage::Result<()> {
let p = SyncPage::connect("http://127.0.0.1:9222")?; // takes over the active tab
p.get("https://example.com")?;
p.type_text("input[name=q]", "rust")?;
p.click_ele("#submit")?;
println!("{} â {} cookies", p.title()?, p.cookies()?.len());
Ok(())
}
```
## Locator syntax
Text/attribute operators follow DrissionPage: `=` exact, `:` contains, `^` starts-with, `$` ends-with.
| `#id`, `.class`, `tag`, `css:âĻ` | CSS |
| `xpath:âĻ` | XPath |
| `@class=btn` / `@class:btn` / `@class^btn` / `@class$btn` | attribute exact / contains / prefix / suffix |
| `text=Login` / `text:Login` / `text^Log` / `text$in` | text exact / contains / prefix / suffix |
| `tag:div@@class=x@@text:y` | **same-element AND** (all conditions) |
| `@|class=a@|class=b` | **same-element OR** (any condition) |
| `a@@@b@@@c` | descendant chain (rpage extension) |
Non-CSS locators fall back to a JS `document.evaluate` XPath query automatically.
## Capabilities
Below is a tour of the high-value APIs. The **full API (580+ methods) is on
[docs.rs/rpage](https://docs.rs/rpage)**.
### Elements
```rust
let el = page.ele("#item").await?;
el.click().await?; // CDP click, JS fallback, waits actionable
el.fill("text").await?; // clear + type (Unicode)
el.right_click().await?; el.double_click().await?;
el.drag_to(&target).await?; // or drag_to_offset(dx, dy)
el.select("Option").await?; // <select>
el.upload_file("/path").await?;
el.is_visible().await; el.is_in_viewport().await; el.is_alive().await; // states
let parent = el.parent().await?; // parent/first_child/next/prev/children
el.wait_for_visible().await?; // + hidden/enabled/clickable/stale/text/attribute
```
### Semantic locators (Playwright `get_by_*`)
```rust
page.get_by_text("Login").await?;
page.get_by_role("button").await?; // explicit + implicit ARIA roles
page.get_by_label("Username").await?; // aria-label / <label for> / wrapping
page.get_by_placeholder("Search").await?;
page.get_by_test_id("submit").await?; // data-testid
```
### Network capture & mocking
```rust
// Raw CDP passthrough for anything not wrapped:
page.run_cdp("Page.getLayoutMetrics", serde_json::json!({})).await?;
// Capture full request+response+body (DrissionPage listen.wait/steps):
page.listen_start().await?;
page.ele("#load").await?.click().await?;
let pkt = page.wait_data_packet("/api/data", 10).await?; // wait for one
println!("{} {} -> {}", pkt.status, pkt.url, pkt.body_text());
for p in page.data_packets("/api/").await { /* all matches */ }
// Mock a response without hitting the network (Playwright route.fulfill):
let guard = page.enable_intercept("*://*/api/*").await?;
page.click_ele("#load").await?;
for req in guard.paused_requests() {
guard.fulfill_json(req.request_id.as_ref(), r#"{"mock":true}"#).await?;
// or: continue_request(id, redirect) / fail_request(id) /
// fulfill_request(id, status, &headers, body)
}
guard.disable().await?;
```
### Static-snapshot elements (DrissionPage `s_ele`)
```rust
let rows = page.s_eles("table tr").await?; // parse current HTML once, no live CDP
for row in &rows { println!("{}", row.text()); }
```
### Dual mode, cookies, lifecycle
```rust
page.to_session().await?; // browser â HTTP
let resp = page.session_get(url).await?;
page.to_chromium().await?; // HTTP â browser
page.save_cookies_to_file("c.json").await?;
page.quit().await?;
```
### More (see docs.rs)
Tabs, scrolling, screenshots/PDF, iframes, alerts, downloads, console &
WebSocket capture, performance metrics, init scripts & CSS injection, device
emulation (DPR/touch/geolocation/timezone), window management, `ActionChain`,
stealth, and an **Agent interface** (`interactive_elements()`,
`page_snapshot()`, `smart_click()`, `smart_fill()`) for LLM-driven automation.
## Configuration
```rust
use rpage::{WebPage, WebPageOptions, ChromiumOptions};
let page = WebPage::with_options(WebPageOptions {
chromium: ChromiumOptions::builder()
.headless(true)
.debug_port(19222)
.proxy("http://127.0.0.1:7890")
.build(),
..Default::default()
}).await?;
```
Set `RPAGE_CHROME_PATH` to point at a specific Chrome/Chromium binary.
## Requirements
- A locally installed Chrome or Chromium.
- Rust 1.75+ (2021 edition).
## Stability
`rpage` follows [SemVer](https://semver.org/). Starting at **1.0**, breaking
API changes will only land in a new major version.
## License
MIT