欢迎光临
我们一直在努力

OpenClaw Canvas 执行:JavaScript 注入实战

目录

    • 摘要
    • 1. 引言 – JavaScript 执行的价值
      • 1.1 JS 执行应用场景
      • 1.2 eval 功能概览
      • 1.3 执行方式
    • 2. 基本执行操作
      • 2.1 执行简单脚本
      • 2.2 获取页面信息
      • 2.3 执行多行脚本
    • 3. 数据获取
      • 3.1 获取元素内容
      • 3.2 获取表单数据
      • 3.3 获取所有输入值
      • 3.4 获取计算样式
    • 4. DOM 操作
      • 4.1 修改元素内容
      • 4.2 修改元素HTML
      • 4.3 添加元素
      • 4.4 删除元素
      • 4.5 修改属性
    • 5. 样式控制
      • 5.1 修改内联样式
      • 5.2 添加/删除类
      • 5.3 主题切换
    • 6. 事件处理
      • 6.1 触发点击
      • 6.2 触发表单提交
      • 6.3 触发自定义事件
    • 7. 实战案例一:动态数据更新
      • 7.1 场景描述
      • 7.2 实现代码
      • 7.3 更新图表
    • 8. 实战案例二:表单自动填充
      • 8.1 场景描述
      • 8.2 实现代码
    • 9. 实战案例三:内容提取
      • 9.1 场景描述
      • 9.2 实现代码
    • 10. 高级技巧
      • 10.1 异步操作
      • 10.2 等待元素
      • 10.3 批量操作
    • 11. 安全注意事项
      • 11.1 安全风险
      • 11.2 安全实践
    • 12. 总结
      • 12.1 核心要点
      • 12.2 最佳实践
      • 12.3 下一步
    • 参考资料

摘要

本文深入探讨 OpenClaw Canvas 的 JavaScript 执行功能。从基本执行、数据获取、DOM操作到高级应用,全面解析如何通过 eval 注入 JavaScript 实现灵活的界面控制。通过实际案例演示数据提取、动态更新、事件处理等场景,帮助开发者掌握 Canvas 的高级控制能力。⚡


1. 引言 – JavaScript 执行的价值

1.1 JS 执行应用场景

场景说明示例
数据获取 获取页面数据 读取表单值
DOM操作 修改页面元素 更新内容
事件触发 触发页面事件 点击按钮
动态更新 实时更新内容 刷新数据
样式控制 动态修改样式 切换主题

1.2 eval 功能概览

#mermaid-svg-36LXF38sEDLZeeCI{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-36LXF38sEDLZeeCI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-36LXF38sEDLZeeCI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-36LXF38sEDLZeeCI .error-icon{fill:#552222;}#mermaid-svg-36LXF38sEDLZeeCI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-36LXF38sEDLZeeCI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-36LXF38sEDLZeeCI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-36LXF38sEDLZeeCI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-36LXF38sEDLZeeCI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-36LXF38sEDLZeeCI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-36LXF38sEDLZeeCI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-36LXF38sEDLZeeCI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-36LXF38sEDLZeeCI .marker.cross{stroke:#333333;}#mermaid-svg-36LXF38sEDLZeeCI svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-36LXF38sEDLZeeCI p{margin:0;}#mermaid-svg-36LXF38sEDLZeeCI .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-36LXF38sEDLZeeCI .cluster-label text{fill:#333;}#mermaid-svg-36LXF38sEDLZeeCI .cluster-label span{color:#333;}#mermaid-svg-36LXF38sEDLZeeCI .cluster-label span p{background-color:transparent;}#mermaid-svg-36LXF38sEDLZeeCI .label text,#mermaid-svg-36LXF38sEDLZeeCI span{fill:#333;color:#333;}#mermaid-svg-36LXF38sEDLZeeCI .node rect,#mermaid-svg-36LXF38sEDLZeeCI .node circle,#mermaid-svg-36LXF38sEDLZeeCI .node ellipse,#mermaid-svg-36LXF38sEDLZeeCI .node polygon,#mermaid-svg-36LXF38sEDLZeeCI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-36LXF38sEDLZeeCI .rough-node .label text,#mermaid-svg-36LXF38sEDLZeeCI .node .label text,#mermaid-svg-36LXF38sEDLZeeCI .image-shape .label,#mermaid-svg-36LXF38sEDLZeeCI .icon-shape .label{text-anchor:middle;}#mermaid-svg-36LXF38sEDLZeeCI .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-36LXF38sEDLZeeCI .rough-node .label,#mermaid-svg-36LXF38sEDLZeeCI .node .label,#mermaid-svg-36LXF38sEDLZeeCI .image-shape .label,#mermaid-svg-36LXF38sEDLZeeCI .icon-shape .label{text-align:center;}#mermaid-svg-36LXF38sEDLZeeCI .node.clickable{cursor:pointer;}#mermaid-svg-36LXF38sEDLZeeCI .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-36LXF38sEDLZeeCI .arrowheadPath{fill:#333333;}#mermaid-svg-36LXF38sEDLZeeCI .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-36LXF38sEDLZeeCI .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-36LXF38sEDLZeeCI .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-36LXF38sEDLZeeCI .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-36LXF38sEDLZeeCI .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-36LXF38sEDLZeeCI .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-36LXF38sEDLZeeCI .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-36LXF38sEDLZeeCI .cluster text{fill:#333;}#mermaid-svg-36LXF38sEDLZeeCI .cluster span{color:#333;}#mermaid-svg-36LXF38sEDLZeeCI div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-36LXF38sEDLZeeCI .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-36LXF38sEDLZeeCI rect.text{fill:none;stroke-width:0;}#mermaid-svg-36LXF38sEDLZeeCI .icon-shape,#mermaid-svg-36LXF38sEDLZeeCI .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-36LXF38sEDLZeeCI .icon-shape p,#mermaid-svg-36LXF38sEDLZeeCI .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-36LXF38sEDLZeeCI .icon-shape .label rect,#mermaid-svg-36LXF38sEDLZeeCI .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-36LXF38sEDLZeeCI .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-36LXF38sEDLZeeCI .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-36LXF38sEDLZeeCI :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

eval 执行

执行类型

数据读取

DOM修改

事件触发

样式控制

返回结果

1.3 执行方式

方式说明返回值
同步执行 立即执行并返回
异步执行 异步执行 Promise

2. 基本执行操作

2.1 执行简单脚本

result = canvas(
action="eval",
javaScript="1 + 1"
)
# result = 2

2.2 获取页面信息

# 获取标题
title = canvas(
action="eval",
javaScript="document.title"
)

# 获取URL
url = canvas(
action="eval",
javaScript="window.location.href"
)

# 获取HTML
html = canvas(
action="eval",
javaScript="document.documentElement.outerHTML"
)

2.3 执行多行脚本

result = canvas(
action="eval",
javaScript="""
const title = document.title;
const url = window.location.href;
JSON.stringify({ title, url });
"""

)


3. 数据获取

3.1 获取元素内容

def get_element_text(selector):
"""获取元素文本"""
return canvas(
action="eval",
javaScript=f"""
document.querySelector('
{selector}').textContent
"""

)

# 使用示例
text = get_element_text("#main-title")

3.2 获取表单数据

def get_form_data(form_selector):
"""获取表单数据"""
return canvas(
action="eval",
javaScript=f"""
const form = document.querySelector('
{form_selector}');
const formData = new FormData(form);
const data = {{}};
for (let [key, value] of formData.entries()) {{
data[key] = value;
}}
JSON.stringify(data);
"""

)

3.3 获取所有输入值

def get_all_inputs():
"""获取所有输入框的值"""
return canvas(
action="eval",
javaScript="""
const inputs = document.querySelectorAll('input, textarea, select');
const data = {};
inputs.forEach(input => {
const name = input.name || input.id;
if (name) {
data[name] = input.value;
}
});
JSON.stringify(data);
"""

)

3.4 获取计算样式

def get_computed_style(selector, property):
"""获取计算样式"""
return canvas(
action="eval",
javaScript=f"""
const element = document.querySelector('
{selector}');
window.getComputedStyle(element).getPropertyValue('
{property}');
"""

)


4. DOM 操作

4.1 修改元素内容

def set_element_text(selector, text):
"""设置元素文本"""
canvas(
action="eval",
javaScript=f"""
document.querySelector('
{selector}').textContent = '{text}';
"""

)

4.2 修改元素HTML

def set_element_html(selector, html):
"""设置元素HTML"""
canvas(
action="eval",
javaScript=f"""
document.querySelector('
{selector}').innerHTML = `{html}`;
"""

)

4.3 添加元素

def append_element(parent_selector, html):
"""添加子元素"""
canvas(
action="eval",
javaScript=f"""
const parent = document.querySelector('
{parent_selector}');
const div = document.createElement('div');
div.innerHTML = `
{html}`;
parent.appendChild(div.firstElementChild);
"""

)

4.4 删除元素

def remove_element(selector):
"""删除元素"""
canvas(
action="eval",
javaScript=f"""
const element = document.querySelector('
{selector}');
if (element) element.remove();
"""

)

4.5 修改属性

def set_attribute(selector, attr, value):
"""设置属性"""
canvas(
action="eval",
javaScript=f"""
document.querySelector('
{selector}').setAttribute('{attr}', '{value}');
"""

)


5. 样式控制

5.1 修改内联样式

def set_style(selector, property, value):
"""设置样式"""
canvas(
action="eval",
javaScript=f"""
document.querySelector('
{selector}').style.{property} = '{value}';
"""

)

# 使用示例
set_style('#header', 'backgroundColor', '#667eea')
set_style('#content', 'display', 'none')

5.2 添加/删除类

def add_class(selector, class_name):
"""添加类"""
canvas(
action="eval",
javaScript=f"""
document.querySelector('
{selector}').classList.add('{class_name}');
"""

)

def remove_class(selector, class_name):
"""删除类"""
canvas(
action="eval",
javaScript=f"""
document.querySelector('
{selector}').classList.remove('{class_name}');
"""

)

def toggle_class(selector, class_name):
"""切换类"""
canvas(
action="eval",
javaScript=f"""
document.querySelector('
{selector}').classList.toggle('{class_name}');
"""

)

5.3 主题切换

def toggle_theme():
"""切换主题"""
canvas(
action="eval",
javaScript="""
document.body.classList.toggle('dark-theme');
"""

)


6. 事件处理

6.1 触发点击

def trigger_click(selector):
"""触发点击事件"""
canvas(
action="eval",
javaScript=f"""
document.querySelector('
{selector}').click();
"""

)

6.2 触发表单提交

def submit_form(form_selector):
"""提交表单"""
canvas(
action="eval",
javaScript=f"""
document.querySelector('
{form_selector}').submit();
"""

)

6.3 触发自定义事件

def trigger_custom_event(selector, event_name, detail=None):
"""触发自定义事件"""
detail_json = json.dumps(detail) if detail else '{}'
canvas(
action="eval",
javaScript=f"""
const event = new CustomEvent('
{event_name}', {{ detail: {detail_json} }});
document.querySelector('
{selector}').dispatchEvent(event);
"""

)


7. 实战案例一:动态数据更新

7.1 场景描述

实时更新 Canvas 中的数据展示。

7.2 实现代码

def update_dashboard(data):
"""更新仪表盘数据"""
# 构建更新脚本
updates = []
for key, value in data.items():
updates.append(f"document.getElementById('{key}').textContent = '{value}';")

canvas(
action="eval",
javaScript="\\n".join(updates)
)

# 使用示例
update_dashboard({
"total-users": "1,234",
"active-users": "567",
"requests": "12,345",
"success-rate": "99.5%"
})

7.3 更新图表

def update_chart(chart_id, new_data):
"""更新图表数据"""
canvas(
action="eval",
javaScript=f"""
const chart = Chart.getChart('
{chart_id}');
if (chart) {{
chart.data.datasets[0].data =
{json.dumps(new_data)};
chart.update();
}}
"""

)


8. 实战案例二:表单自动填充

8.1 场景描述

自动填充表单数据。

8.2 实现代码

def fill_form(data):
"""填充表单"""
fill_scripts = []

for field, value in data.items():
script = f"""
const field = document.querySelector('[name="
{field}"], #{field}');
if (field) {{
if (field.type === 'checkbox' || field.type === 'radio') {{
field.checked =
{str(value).lower()};
}} else if (field.tagName === 'SELECT') {{
field.value = '
{value}';
}} else {{
field.value = '
{value}';
}}
}}
"""

fill_scripts.append(script)

canvas(
action="eval",
javaScript="\\n".join(fill_scripts)
)

# 使用示例
fill_form({
"username": "admin",
"email": "admin@example.com",
"role": "admin",
"active": True
})


9. 实战案例三:内容提取

9.1 场景描述

从 Canvas 中提取结构化数据。

9.2 实现代码

def extract_table_data(table_selector):
"""提取表格数据"""
return canvas(
action="eval",
javaScript=f"""
const table = document.querySelector('
{table_selector}');
const rows = table.querySelectorAll('tr');
const data = [];

rows.forEach(row => {{
const cells = row.querySelectorAll('td, th');
const rowData = [];
cells.forEach(cell => rowData.push(cell.textContent.trim()));
data.push(rowData);
}});

JSON.stringify(data);
"""
)

def extract_list_data(list_selector):
"""提取列表数据"""
return canvas(
action="eval",
javaScript=f"""
const items = document.querySelectorAll('
{list_selector} > li');
const data = [];

items.forEach(item => {{
data.push(item.textContent.trim());
}});

JSON.stringify(data);
"""
)


10. 高级技巧

10.1 异步操作

def async_operation():
"""异步操作"""
return canvas(
action="eval",
javaScript="""
(async () => {
const response = await fetch('/api/data');
const data = await response.json();
return JSON.stringify(data);
})()
"""

)

10.2 等待元素

def wait_for_element(selector, timeout=5000):
"""等待元素出现"""
return canvas(
action="eval",
javaScript=f"""
(async () => {{
const start = Date.now();
while (Date.now() – start <
{timeout}) {{
const element = document.querySelector('
{selector}');
if (element) return true;
await new Promise(r => setTimeout(r, 100));
}}
return false;
}})()
"""

)

10.3 批量操作

def batch_dom_operations(operations):
"""批量DOM操作"""
scripts = []

for op in operations:
if op['type'] == 'setText':
scripts.append(f"document.querySelector('{op['selector']}').textContent = '{op['value']}';")
elif op['type'] == 'setHtml':
scripts.append(f"document.querySelector('{op['selector']}').innerHTML = `{op['value']}`;")
elif op['type'] == 'click':
scripts.append(f"document.querySelector('{op['selector']}').click();")

canvas(
action="eval",
javaScript="\\n".join(scripts)
)


11. 安全注意事项

11.1 安全风险

风险说明防护措施
XSS攻击 注入恶意脚本 转义用户输入
数据泄露 读取敏感数据 权限控制
无限循环 死循环脚本 超时限制
DOM破坏 破坏页面结构 操作验证

11.2 安全实践

def safe_eval(script, user_input):
"""安全的执行"""
# 转义用户输入
escaped = user_input.replace("'", "\\\\'").replace('"', '\\\\"')

# 使用参数化脚本
safe_script = script.replace('{input}', escaped)

return canvas(action="eval", javaScript=safe_script)


12. 总结

12.1 核心要点

要点说明
数据获取 读取页面内容和数据
DOM操作 修改元素和结构
样式控制 动态修改样式
事件触发 触发页面事件

12.2 最佳实践

  • 转义用户输入
  • 使用参数化脚本
  • 添加错误处理
  • 限制执行时间

12.3 下一步

  • 第54篇:OpenClaw Canvas 截图:页面捕获与保存
  • 第55篇:OpenClaw Canvas A2UI:交互式界面开发

参考资料

  • OpenClaw 官方文档
  • JavaScript DOM操作
  • XSS防护

赞(0)
未经允许不得转载:171主机测评 » OpenClaw Canvas 执行:JavaScript 注入实战
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址