插件中延迟等待功能的实现
function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } (async () => { while(true) { console.log("Start"); await delay(5000); console.log("End"); // 5秒后应该输出 await delay(5000); } })();
网页中模拟用户输入操作
我们唯一客服浏览器插件实现了自动化发评论
content.js
function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } (async function() { while(true) { var arr = ["你好", "加油"]; for (let value of arr) { console.log(value); chrome.runtime.sendMessage({ action: "simulateInput", xpath: '//div[@contenteditable="true"]', input: value }); await delay(10000); } } })();
background.js
chrome.runtime.onMessage.addListener( function(request, sender, sendResponse) { // 处理模拟输入事件 if (request.action === "simulateInput") { let xpath=request.xpath; executeSimulateEditableInput(sender.tab.id,xpath,request.input) } }); // 发送 POST 请求 function executeSimulateEditableInput(tabId, xpath, input) { const code = ` function simulateEditableInput(xpath, input) { const result = document.evaluate( xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); const element = result.singleNodeValue; if (element) { // 确保元素可编辑 element.focus(); element.value = input; element.innerHTML = input; // 触发完整事件链 ['focus', 'input', 'change'].forEach(eventType => { element.dispatchEvent(new Event(eventType, { bubbles: true, cancelable: true })); }); } } simulateEditableInput(${JSON.stringify(xpath)}, ${JSON.stringify(input)}); `; chrome.debugger.attach({ tabId }, '1.3', () => { chrome.debugger.sendCommand({ tabId }, 'Runtime.evaluate', { expression: code, awaitPromise: true }, (result) => { console.log('Execution result:', result); chrome.debugger.detach({ tabId }); }); }); }
具体原理
- 消息监听部分:
- 监听扩展内部发送的消息
- 当收到
action: "simulateInput"
的消息时,提取 XPath 选择器和输入内容 - 调用
executeSimulateEditableInput
函数执行实际模拟
- 调试器注入部分:
- 使用
chrome.debugger.attach
附加到目标标签页 - 通过 Debugger Protocol 的
Runtime.evaluate
命令注入代码 - 执行完成后断开调试器连接
- 核心模拟逻辑(在目标页面中执行的代码):
- 使用
document.evaluate
通过 XPath 查找目标元素 - 对找到的元素执行以下操作:
focus()
:模拟获取焦点- 设置
value
和innerHTML
属性 - 依次触发三个关键事件:
focus
事件 - 模拟元素获得焦点input
事件 - 模拟用户输入change
事件 - 模拟内容变更确认
- 事件触发机制:
- 使用
dispatchEvent
创建并派发合成事件 - 设置
bubbles: true
让事件冒泡 - 设置
cancelable: true
允许事件被取消
为什么使用 Debugger API
- 普通内容脚本可能无法完全模拟所有输入场景
- Debugger API 提供了更底层的页面控制能力
- 可以确保事件触发的完整性和真实性
注意事项
- 需要扩展拥有
debugger
权限 - 这种方式会短暂中断页面上的所有调试会话
- 相比直接内容脚本注入,这种方式能更好地模拟真实用户交互
这种实现方式特别适合需要高度模拟真实用户输入的场景,比如自动化测试或表单填写扩展。