feat(text): frame-aware text extraction — get text --all-frames / --main + frames (#27)

On listing/marketplace pages (Yahoo Auctions, Rakuten, Mercari shops) the
seller's description lives in a child frame or under a related-items sidebar,
so 'get text body' returned only header/nav boilerplate.

- get text --all-frames: aggregate visible text across every reachable frame.
  Same-process child frames are read via Page.createIsolatedWorld; OOPIFs via
  their auto-attached debugger session (iframe_sessions). Each non-top frame is
  labelled with a '----- frame [kind] url -----' separator.
- get text --main: readability-lite — prefer the densest <main>/<article>
  region over the whole body, dropping global header/nav/footer chrome.
- frames: enumerate frames (kind + url + per-frame text length) so an agent can
  see where a page's text actually lives and pick the right read.

Verified live: inline srcdoc frame text aggregated through --all-frames; Yahoo
Auctions <main> (2881 chars) extracted via --main, stripping the Yahoo header.
This commit is contained in:
leeguooooo
2026-06-15 12:51:59 +09:00
parent f7a657ac46
commit 2707ceb1c4
5 changed files with 370 additions and 1 deletions
+34
View File
@@ -342,6 +342,34 @@ pub fn print_response_with_opts(resp: &Response, action: Option<&str>, opts: &Ou
}
return;
}
// Frame list (`chrome-use frames`)
if action == Some("frames") {
if let Some(list) = data.get("frames").and_then(|v| v.as_array()) {
let count = list.len();
println!(
"{}",
color::bold(&format!("{} frame{}", count, if count == 1 { "" } else { "s" }))
);
for f in list {
let idx = f.get("index").and_then(|v| v.as_i64()).unwrap_or(0);
let kind = f.get("kind").and_then(|v| v.as_str()).unwrap_or("?");
let url = f.get("url").and_then(|v| v.as_str()).unwrap_or("");
let len = f.get("textLen").and_then(|v| v.as_i64()).unwrap_or(0);
println!(
" [{}] {:<6} {} chars {}",
idx,
kind,
len,
color::dim(if url.is_empty() { "(about:blank)" } else { url })
);
}
eprintln!(
"{}",
color::dim("read everything with: chrome-use get text --all-frames")
);
}
return;
}
// Title
if let Some(title) = data.get("title").and_then(|v| v.as_str()) {
println!("{}", title);
@@ -1930,6 +1958,8 @@ Retrieves various types of information from elements or the page.
Subcommands:
text <selector> Get text content of element
text --all-frames Aggregate text across ALL frames (incl. iframes)
text --main Main-content text only (skip nav/header/sidebar)
html <selector> Get inner HTML of element
value <selector> Get value of input element
attr <selector> <name> Get attribute value
@@ -1946,6 +1976,9 @@ Global Options:
Examples:
chrome-use get text @e1
chrome-use get text --all-frames # read iframed content (listing pages)
chrome-use get text --main # main content, no nav/sidebar boilerplate
chrome-use frames # list frames + where the text lives
chrome-use get html "#content"
chrome-use get value "#email-input"
chrome-use get attr "#link" href
@@ -3155,6 +3188,7 @@ Navigation:
Get Info: chrome-use get <what> [selector]
text, html, value, attr <name>, title, url, count, box, styles, cdp-url
text --all-frames (cross-frame), text --main (no boilerplate), frames (list)
Check State: chrome-use is <what> <selector>
visible, enabled, checked