Skip to main content

PageHandle

Struct PageHandle 

Source
pub struct PageHandle { /* private fields */ }
Expand description

§Example

use stygian_browser::{BrowserPool, BrowserConfig};
use stygian_browser::page::WaitUntil;
use std::time::Duration;

let pool = BrowserPool::new(BrowserConfig::default()).await?;
let handle = pool.acquire().await?;
let mut page = handle.browser().expect("valid browser").new_page().await?;
page.navigate("https://example.com", WaitUntil::DomContentLoaded, Duration::from_secs(30)).await?;
let html = page.content().await?;
drop(page); // closes the tab
handle.release().await;

Implementations§

Source§

impl PageHandle

Source

pub async fn navigate( &mut self, url: &str, condition: WaitUntil, nav_timeout: Duration, ) -> Result<()>

§Errors

the CDP call fails.

Source

pub async fn wait_for_selector( &self, selector: &str, wait_timeout: Duration, ) -> Result<()>

§Errors

within the given timeout.

Source

pub async fn set_resource_filter( &mut self, filter: ResourceFilter, ) -> Result<()>

Enables Fetch interception and spawns a background task that continues allowed requests and fails blocked ones with BlockedByClient. Any previously set filter task is cancelled first.

§Errors
Source

pub async fn url(&self) -> Result<String>

Return the current page URL (post-navigation, post-redirect).

internally by save_cookies; no extra network request is made. Returns an empty string if the URL is not yet set

§Errors

BrowserError::Timeout if it exceeds cdp_timeout.

§Example
use stygian_browser::{BrowserPool, BrowserConfig};
use stygian_browser::page::WaitUntil;
use std::time::Duration;

let pool = BrowserPool::new(BrowserConfig::default()).await?;
let handle = pool.acquire().await?;
let mut page = handle.browser().expect("valid browser").new_page().await?;
page.navigate("https://example.com", WaitUntil::DomContentLoaded, Duration::from_secs(30)).await?;
let url = page.url().await?;
println!("Final URL after redirects: {url}");
Source

pub fn status_code(&self) -> Result<Option<u16>>

Return the HTTP status code of the most recent main-frame navigation.

The status is captured from the Network.responseReceived CDP event wired up inside navigate, so it reflects the final response after any server-side redirects.

navigations, when navigate has not yet been called, or if the network event subscription failed.

§Errors
§Example
use stygian_browser::{BrowserPool, BrowserConfig};
use stygian_browser::page::WaitUntil;
use std::time::Duration;

let pool = BrowserPool::new(BrowserConfig::default()).await?;
let handle = pool.acquire().await?;
let mut page = handle.browser().expect("valid browser").new_page().await?;
page.navigate("https://example.com", WaitUntil::DomContentLoaded, Duration::from_secs(30)).await?;
if let Some(code) = page.status_code()? {
    println!("HTTP {code}");
}
Source

pub async fn title(&self) -> Result<String>

Return the page’s <title> text.

§Errors
Source

pub async fn content(&self) -> Result<String>

Return the page’s full outer HTML.

§Errors
Source

pub async fn query_selector_all( &self, selector: &str, ) -> Result<Vec<NodeHandle>>

lightweight NodeHandles backed by CDP RemoteObjectIds.

No HTML serialisation occurs — the browser’s in-memory DOM is queried directly over the CDP connection, eliminating the page.content() + scraper::Html::parse_document round-trip.

§Errors

BrowserError::Timeout if it exceeds cdp_timeout.

§Example
use stygian_browser::{BrowserPool, BrowserConfig, WaitUntil};
use std::time::Duration;

let pool = BrowserPool::new(BrowserConfig::default()).await?;
let handle = pool.acquire().await?;
let mut page = handle.browser().expect("valid browser").new_page().await?;
page.navigate("https://example.com", WaitUntil::DomContentLoaded, Duration::from_secs(30)).await?;
    let ux_type = node.attr("data-ux").await?;
    let text    = node.text_content().await?;
    println!("{ux_type:?}: {text}");
Source

pub async fn eval<T: DeserializeOwned>(&self, script: &str) -> Result<T>

Evaluate arbitrary JavaScript and return the result as T.

§Errors

deserialization error.

Source

pub async fn save_cookies(&self) -> Result<Vec<Cookie>>

§Errors
Source

pub async fn inject_cookies(&self, cookies: &[SessionCookie]) -> Result<()>

SessionSnapshot and without requiring a direct chromiumoxide dependency in calling code.

Individual cookie failures are logged as warnings and do not abort the remaining cookies.

§Errors

call exceeds cdp_timeout.

§Example
use stygian_browser::{BrowserPool, BrowserConfig};
use stygian_browser::session::SessionCookie;
use std::time::Duration;

let pool = BrowserPool::new(BrowserConfig::default()).await?;
let handle = pool.acquire().await?;
let page = handle.browser().expect("valid browser").new_page().await?;
let cookies = vec![SessionCookie {
    name: "session".to_string(),
    value: "abc123".to_string(),
    domain: ".example.com".to_string(),
    path: "/".to_string(),
    expires: -1.0,
    http_only: true,
    secure: true,
    same_site: "Lax".to_string(),
}];
page.inject_cookies(&cookies).await?;
Source

pub async fn screenshot(&self) -> Result<Vec<u8>>

Capture a screenshot of the current page as PNG bytes.

them in-memory.

§Errors

command fails, or BrowserError::Timeout if it exceeds cdp_timeout.

§Example
use stygian_browser::{BrowserPool, BrowserConfig, WaitUntil};
use std::{time::Duration, fs};

let pool = BrowserPool::new(BrowserConfig::default()).await?;
let handle = pool.acquire().await?;
let mut page = handle.browser().expect("valid browser").new_page().await?;
let png = page.screenshot().await?;
fs::write("screenshot.png", &png).unwrap();
Source

pub const fn inner(&self) -> &Page

Borrow the underlying chromiumoxide [Page].

Source

pub async fn close(self) -> Result<()>

Close this page (tab).

Source§

impl PageHandle

Source

pub async fn verify_stealth(&self) -> Result<DiagnosticReport>

Run all built-in stealth detection checks against the current page.

Iterates crate::diagnostic::all_checks, evaluates each check’s JavaScript via CDP Runtime.evaluate, and returns an aggregate crate::diagnostic::DiagnosticReport.

recorded as failing checks and do not abort the whole run.

§Errors

Individual check failures are captured in the report.

§Example
use stygian_browser::{BrowserPool, BrowserConfig};
use stygian_browser::page::WaitUntil;
use std::time::Duration;

let pool = BrowserPool::new(BrowserConfig::default()).await?;
let handle = pool.acquire().await?;
let browser = handle.browser().expect("valid browser");
let mut page = browser.new_page().await?;
page.navigate("https://example.com", WaitUntil::DomContentLoaded, Duration::from_secs(10)).await?;

let report = page.verify_stealth().await?;
println!("Stealth: {}/{} checks passed", report.passed_count, report.checks.len());
    eprintln!("  FAIL  {}: {}", failure.description, failure.details);
Source

pub async fn verify_stealth_with_transport( &self, observed: Option<TransportObservations>, ) -> Result<DiagnosticReport>

Run stealth checks and attach transport diagnostics (JA3/JA4/HTTP3).

Source§

impl PageHandle

Source

pub async fn extract_all<T>(&self, selector: &str) -> Result<Vec<T>>
where T: Extractable,

All per-node extractions are driven concurrently via [futures::future::try_join_all].

§Errors

fails, or BrowserError::ExtractionFailed if any field extraction fails.

§Example
use stygian_browser::extract::Extract;
use stygian_browser::{BrowserPool, BrowserConfig, WaitUntil};
use std::time::Duration;

#[derive(Extract)]
struct Link {
    href: Option<String>,
}

let pool = BrowserPool::new(BrowserConfig::default()).await?;
let handle = pool.acquire().await?;
let mut page = handle.browser().expect("valid browser").new_page().await?;
page.navigate(
    "https://example.com",
    WaitUntil::DomContentLoaded,
    Duration::from_secs(30),
).await?;
let links: Vec<Link> = page.extract_all::<Link>("nav li").await?;
Source

pub async fn extract_all_with_fallback<T>( &self, selectors: &[&str], ) -> Result<Vec<T>>
where T: Extractable,

Try each selector in selectors in order and return the extracted results from the first selector that matches at least one node.

This is useful when a page may use different markup across versions or A/B variants — supply the preferred selector first and progressively wider fallbacks afterwards.

Returns an empty Vec only when all selectors match zero nodes (i.e. the element is genuinely absent from the page). A non-empty intermediate selector result that then fails during extraction will return an error.

§Errors

Returns BrowserError::CdpError if the selector query fails, or BrowserError::ExtractionFailed if a matched node fails extraction.

§Example
use stygian_browser::extract::Extract;

#[derive(Extract)]
struct Headline { title: String }

// Try modern selector first, fall back to legacy markup.
let items = page
    .extract_all_with_fallback::<Headline>(&["h2.headline", "h2.title", "h2"])
    .await?;
Source

pub async fn extract_resilient<T>(&self, selector: &str) -> Result<Vec<T>>
where T: Extractable,

Extract from every node matching selector, skipping nodes where a required field is absent (i.e. ExtractionError::Missing).

Unlike extract_all, this method is lenient about structural mismatches: nodes that fail with ExtractionError::Missing are silently dropped from the result set. All other extraction errors (CDP failures, stale nodes, nested errors) still propagate as hard failures.

This is useful when scraping heterogeneous lists where some items lack an optional field that your struct treats as required.

§Errors

Returns BrowserError::CdpError if the selector query fails, or BrowserError::ExtractionFailed for non-Missing extraction errors.

§Example
use stygian_browser::extract::Extract;

#[derive(Extract)]
struct Price { amount: String }

// Products without a price tag are silently skipped.
let prices = page.extract_resilient::<Price>(".product").await?;
Source§

impl PageHandle

Source

pub async fn find_similar( &self, reference: &NodeHandle, config: SimilarityConfig, ) -> Result<Vec<SimilarMatch>>

reference, scored by crate::similarity::SimilarityConfig.

NodeHandle::fingerprint), then fingerprints every candidate returned crate::similarity::jaccard_weighted score exceeds config.threshold. Results are ordered by score descending.

§Example
use stygian_browser::{BrowserPool, BrowserConfig, WaitUntil};
use stygian_browser::similarity::SimilarityConfig;
use std::time::Duration;

let pool = BrowserPool::new(BrowserConfig::default()).await?;
let handle = pool.acquire().await?;
let mut page = handle.browser().expect("valid browser").new_page().await?;
page.navigate("https://example.com", WaitUntil::DomContentLoaded, Duration::from_secs(30)).await?;

    let similar = page.find_similar(&reference, SimilarityConfig::default()).await?;
        println!("score={:.2}", m.score);
§Errors

BrowserError::ScriptExecutionFailed if a scoring script fails.

Source§

impl PageHandle

Source

pub async fn warmup(&mut self, options: WarmupOptions) -> Result<WarmupReport>

Warm up a browser session by navigating to options.url and optionally waiting for dynamic resources to settle.

Warmup is idempotent: calling it repeatedly re-navigates and re-warms the same session without adverse side effects.

§Errors

Returns BrowserError::NavigationFailed if the navigation times out or the underlying CDP call fails.

§Example
use stygian_browser::{BrowserPool, BrowserConfig};
use stygian_browser::page::{WarmupOptions, WarmupWait};

let pool = BrowserPool::new(BrowserConfig::default()).await?;
let handle = pool.acquire().await?;
let mut page = handle.browser().expect("valid browser").new_page().await?;

let report = page.warmup(WarmupOptions {
    url: "https://example.com".to_string(),
    wait: WarmupWait::DomContentLoaded,
    timeout_ms: 30_000,
    stabilize_ms: 500,
}).await?;
println!("warmed in {}ms: {}", report.elapsed_ms, report.title);
handle.release().await;
Source

pub async fn refresh( &mut self, options: RefreshOptions, ) -> Result<RefreshReport>

Refresh the current page, retaining all in-browser session state (cookies, localStorage, sessionStorage).

When options.reset_connection is false (default) a standard CDP reload is issued. When true, the current URL is re-navigated, which expresses the caller’s intent to force a new underlying TCP/TLS connection while keeping all browser-side state intact.

Refresh is idempotent: repeated calls simply reload the page again.

§Errors

Returns BrowserError::NavigationFailed if the current URL cannot be determined or the reload times out.

§Example
use stygian_browser::{BrowserPool, BrowserConfig};
use stygian_browser::page::{RefreshOptions, WaitUntil};

let pool = BrowserPool::new(BrowserConfig::default()).await?;
let handle = pool.acquire().await?;
let mut page = handle.browser().expect("valid browser").new_page().await?;
page.navigate(
    "https://example.com",
    WaitUntil::DomContentLoaded,
    std::time::Duration::from_secs(30),
).await?;

let report = page.refresh(RefreshOptions::default()).await?;
println!("refreshed in {}ms", report.elapsed_ms);
handle.release().await;

Trait Implementations§

Source§

impl Drop for PageHandle

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more