5.6 KiB
Raw Blame History

name description tags
dynamic-page-extract 提取SPA/动态渲染页面的完整内容,解决browser_snapshot无法获取JS渲染后DOM的问题
browser
spa
dynamic
scrape
cdp

Dynamic Page Content Extraction

browser_snapshot 获取的是 accessibility tree,JS 动态渲染的内容经常缺失。用 browser_console + CDP 绕过。

核心方法:browser_console(expression=...)

# 获取完整页面文本
result = browser_console(expression="document.body ? document.body.innerText : 'no body'")

# 获取特定元素内容
result = browser_console(expression="document.querySelector('.content')?.innerText")

# 获取所有可见文本(排除script/style)
result = browser_console(expression="""
    Array.from(document.querySelectorAll('p, h1, h2, h3, h4, h5, h6, li, td, th, span, div'))
        .filter(el => el.offsetParent !== null && el.innerText.trim())
        .map(el => el.innerText.trim())
        .join('\\n')
""")

# 获取表格数据
result = browser_console(expression="""
    JSON.stringify(
        Array.from(document.querySelectorAll('table tr')).map(row =>
            Array.from(row.querySelectorAll('td, th')).map(cell => cell.innerText.trim())
        )
    )
""")

等待动态内容

# 等待特定内容出现
for _ in range(20):  # 10秒超时
    result = browser_console(expression="""
        (function() {
            const el = document.querySelector('.result-content');
            return el && el.innerText.trim() ? el.innerText.trim() : 'WAITING';
        })()
    """)
    if 'WAITING' not in str(result):
        break
    terminal("sleep 0.5")

CDP Runtime.evaluate 获取完整 DOM

# 获取完整innerHTML(需设置 allow_unsafe_evaluate: true 或通过 browser_console)
result = browser_console(expression="document.documentElement.outerHTML.substring(0, 50000)")

# 获取body内HTML
result = browser_console(expression="document.body.innerHTML.substring(0, 30000)")

绕过限制

browser_console(expression=...) 在 sandbox 中可能被拦截 fetch/network。使用纯 DOM 读取:

# ✅ 允许 - DOM读取
browser_console(expression="document.querySelector('.price').innerText")

# ❌ 可能被拦截 - 网络请求
browser_console(expression="fetch('/api/data')...")

如需网络请求,用 terminal + curl 替代。

交互操作:查找并点击隐藏/不可见按钮

browser_snapshot 只能看到 accessibility tree 中的元素,bricks 表单的 Submit 按钮经常不在 snapshot ref 中。用 browser_console IIFE 查找并点击:

# 查找 Submit 按钮(bricks 登录表单常见模式)
browser_console(expression="""
    (function(){
        var all = document.querySelectorAll('*');
        for(var i=0;i<all.length;i++){
            if(all[i].textContent.trim()==='Submit'){
                return all[i].tagName+'.'+all[i].className+' id:'+all[i].id
            }
        }
        return 'not found'
    })()
""")

# 点击找到的按钮(browser_console 必须用 IIFE 包裹)
browser_console(expression="(function(){document.getElementById('submit').click(); return 'clicked'})()")

# 匹配文本内容点击工具栏按钮
browser_console(expression="""
    (function(){
        var items = document.querySelectorAll('[class*=toolbar] > div, [class*=htoolbar] > div');
        for(var i=0;i<items.length;i++){
            if(items[i].textContent.includes('产品分销')){
                items[i].click(); return 'clicked:'+items[i].textContent.trim().substring(0,30)
            }
        }
        return 'not found'
    })()
""")

# bricks Tabular 行选择(DOM click 不触发 bricks 内部 selection)
# 解决方法:直接导航到目标 CRUD 页面 + URL filter 参数
browser_navigate('/module/crud_list?filter_field=value')

注意:多行 JS 表达式必须用 IIFE (function(){...})() 包裹,顶层 return 无效。

登录 bricks 应用

bricks 登录表单的 Submit 按钮不可见(不在 snapshot ref 中),用以下流程:

browser_navigate('https://app.com/rbac/user/login.ui')
browser_type(ref='@e10', text='username')
browser_type(ref='@e11', text='password')
# 找到并点击隐藏的 Submit 按钮
browser_console(expression="(function(){document.getElementById('submit').click(); return 'done'})()")
terminal("sleep 3")
# 验证登录成功
browser_navigate('https://app.com/protected_page')
content = browser_console(expression="document.body.innerText.substring(0,200)")

常见模式

SPA 路由页面内容

browser_navigate('https://spa-app.com/dashboard')
# 等2秒让JS渲染
terminal("sleep 2")
content = browser_console(expression="document.querySelector('#app')?.innerText || document.body.innerText")

登录后页面

browser_navigate('https://app.com/login')
browser_type(ref='@e10', text='user')
browser_type(ref='@e11', text='password')
browser_click(ref='@e4')
terminal("sleep 3")  # 等登录完成
content = browser_console(expression="document.querySelector('.dashboard')?.innerText")

无限滚动页面

for i in range(5):
    browser_scroll(direction='down')
    terminal("sleep 1")  # 等新内容加载
content = browser_console(expression="document.body.innerText")

与 browser_snapshot 对比

方法 获取内容 适用场景
browser_snapshot accessibility tree 静态页面、表单交互
browser_console(expression) 真实DOM SPA、动态渲染、数据提取

规则: 如果 browser_snapshot 返回空或不完整,立即切换到 browser_console(expression="document.body.innerText")。