pub struct NodeHandle { /* private fields */ }Expand description
more CDP Runtime.callFunctionOn calls against the held V8 remote object
reference — no HTML serialisation occurs.
A handle becomes stale after page navigation or if the underlying DOM
node is removed. Stale calls return BrowserError::StaleNode so callers
can distinguish them from other CDP failures.
§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 href = node.attr("href").await?;
let text = node.text_content().await?;
println!("{text}: {href:?}");Implementations§
Source§impl NodeHandle
impl NodeHandle
Sourcepub async fn attr(&self, name: &str) -> Result<Option<String>>
pub async fn attr(&self, name: &str) -> Result<Option<String>>
Return a single attribute value, or None if the attribute is absent.
Issues one Runtime.callFunctionOn CDP call (el.getAttribute(name)).
§Errors
invalidated, or BrowserError::Timeout / BrowserError::CdpError
on transport-level failures.
Sourcepub async fn attr_map(&self) -> Result<HashMap<String, String>>
pub async fn attr_map(&self) -> Result<HashMap<String, String>>
Return all attributes as a HashMap<name, value> in a single
CDP round-trip.
Uses DOM.getAttributes (via the chromiumoxide attributes() API)
which returns a flat [name, value, name, value, …] list from the node
description — no per-attribute calls are needed.
§Errors
invalidated.
Sourcepub async fn text_content(&self) -> Result<String>
pub async fn text_content(&self) -> Result<String>
Return the element’s textContent (all text inside, no markup).
Reads the DOM textContent property via a single JS eval — this is the
raw text concatenation of all descendant text nodes, independent of
layout or visibility (unlike innerText).
§Errors
invalidated.
Sourcepub async fn inner_html(&self) -> Result<String>
pub async fn inner_html(&self) -> Result<String>
Sourcepub async fn outer_html(&self) -> Result<String>
pub async fn outer_html(&self) -> Result<String>
Return the element’s outerHTML.
Backwards-compatible thin wrapper around
outer_html_with_strategy using the
default OuterHtmlStrategy::Current strategy. Preserves the
historical return contract: Ok(String) where the string may be
empty when both the primary and fallback backends return empty
payloads.
Callers that need to distinguish an empty payload from a hard failure
— or that want the deeper DOM.getOuterHTML + Rust-side walk path —
should call outer_html_with_strategy
directly.
§Errors
Returns an error when any CDP call the chosen strategy actually
invokes fails — that includes both the primary call and any fallback
call (the XMLSerializer JS fallback for OuterHtmlStrategy::Current,
the DOM.describeNode walk for OuterHtmlStrategy::Recursive).
Errors surface as BrowserError::Timeout (CDP call exceeded
cdp_timeout), BrowserError::StaleNode (the handle was
invalidated mid-call), or BrowserError::CdpError (transport-level
failure).
Empty or partially-empty payloads from any individual backend do
not error — they are flattened to an empty String so the
historical Ok(String) contract is preserved. Callers that need to
distinguish an empty payload from a hard failure should call
outer_html_with_strategy
directly and inspect the OuterHtmlResult variant.
Sourcepub async fn outer_html_with_strategy(
&self,
strategy: OuterHtmlStrategy,
) -> Result<OuterHtmlResult>
pub async fn outer_html_with_strategy( &self, strategy: OuterHtmlStrategy, ) -> Result<OuterHtmlResult>
Return the element’s outerHTML using an explicit resolution strategy.
The OuterHtmlStrategy::Current strategy matches the historical
outer_html path: a Chromium element-level JS
evaluation of this.outerHTML, followed by a JS
new XMLSerializer().serializeToString(this) fallback when the
primary call returns an empty payload.
The OuterHtmlStrategy::Recursive strategy resolves #66 for
sites where the JS-side outerHTML accessor intermittently returns
a truncated or empty payload — most notably Wix Studio / Editor X
pages and large SPAs with deeply nested shadow-DOM subtrees. It
prefers the dedicated Chromium DevTools Protocol command
DOM.getOuterHTML (a single round-trip that performs the
serialisation inside the browser, with shadow-DOM roots included by
default) and falls back to a Rust-side walk that calls
DOM.describeNode with depth = -1 and serialises the resulting
Node tree to HTML locally. Neither path relies on Wix-specific
selectors, attributes, or heuristics — the resolution is entirely
driven by CDP commands Chromium already exposes.
Both strategies return OuterHtmlResult::Empty (rather than
Failed) when every backend returns an empty payload — this is
indistinguishable from “node legitimately empty” at the CDP layer.
§Errors
Returns BrowserError::Timeout if the primary CDP call exceeds
cdp_timeout, BrowserError::StaleNode if the handle was
invalidated, or BrowserError::CdpError on transport-level
failure.
§Example
use stygian_browser::page::OuterHtmlStrategy;
// Use the deep-resolution path for SPA / Wix Studio / shadow-DOM pages.
let html = handle
.outer_html_with_strategy(OuterHtmlStrategy::Recursive)
.await?;Sourcepub async fn ancestors(&self) -> Result<Vec<String>>
pub async fn ancestors(&self) -> Result<Vec<String>>
Executes a single Runtime.callFunctionOn JavaScript function that
walks parentElement and collects tag names — no repeated CDP calls.
["p", "article", "body", "html"]§Errors
invalidated, or BrowserError::ScriptExecutionFailed when CDP
Sourcepub async fn children_matching(&self, selector: &str) -> Result<Vec<Self>>
pub async fn children_matching(&self, selector: &str) -> Result<Vec<Self>>
§Errors
invalidated, or BrowserError::CdpError on transport failure.
Sourcepub async fn parent(&self) -> Result<Option<Self>>
pub async fn parent(&self) -> Result<Option<Self>>
Return the immediate parent element, or None if this element has no
parent (i.e. it is the document root).
Issues a single Runtime.callFunctionOn CDP call that temporarily tags
the parent element with a unique attribute, then resolves it via a
CSS attribute selector.
§Errors
Returns an error if the CDP call fails or the page handle is invalidated.
§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?;
if let Some(parent) = nodes[0].parent().await? {
let html = parent.outer_html().await?;
println!("parent: {}", &html[..html.len().min(80)]);
}Sourcepub async fn next_sibling(&self) -> Result<Option<Self>>
pub async fn next_sibling(&self) -> Result<Option<Self>>
Return the next element sibling, or None if this element is the last
child of its parent.
Uses nextElementSibling (skips text/comment nodes).
§Errors
invalidated.
§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?;
if let Some(next) = nodes[0].next_sibling().await? {
println!("next sibling: {}", next.text_content().await?);
}Sourcepub async fn previous_sibling(&self) -> Result<Option<Self>>
pub async fn previous_sibling(&self) -> Result<Option<Self>>
Return the previous element sibling, or None if this element is the
first child of its parent.
Uses previousElementSibling (skips text/comment nodes).
§Errors
invalidated.
§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?;
if let Some(prev) = nodes[1].previous_sibling().await? {
println!("prev sibling: {}", prev.text_content().await?);
}Source§impl NodeHandle
impl NodeHandle
Sourcepub async fn fingerprint(&self) -> Result<ElementFingerprint>
pub async fn fingerprint(&self) -> Result<ElementFingerprint>
node.
Issues a single Runtime.callFunctionOn JS eval that extracts the tag,
class list, attribute names, and body-depth in one round-trip.
§Errors
invalidated, or BrowserError::ScriptExecutionFailed if the script
produces unexpected output.