如何优化Chrome代码片段实现Microsoft Forms单次自动填充?
解决Microsoft Forms动态表单单次自动填充问题
问题场景
- 表单动态性极强,例如选择「None of the above」单选按钮后才会显示后续问题
- 采用关键词匹配定位问题,但存在关键词重复的情况
- 当前实现需多次执行才能完成所有填充,尤其文本输入框填充失败率高,需要实现单次运行完成所有答案填充
改进后的代码
// 关键词与答案映射,按表单出现顺序排列 const questionsAndAnswers = [ { questionKeyword: "first", answerText: "None of the above" }, { questionKeyword: "second", answerText: "222222" }, { questionKeyword: "third?", answerText: "333333" }, { questionKeyword: "fourth", answerText: "444444" }, { questionKeyword: "fifth", answerText: "Yes" }, { questionKeyword: "second", answerText: "222222" }, { questionKeyword: "third?", answerText: "333333" }, { questionKeyword: "fourth", answerText: "444444" }, { questionKeyword: "fifth", answerText: "Yes" } ]; // 标记已处理的问题容器,避免重复匹配关键词 const processedContainers = new WeakSet(); // 标准化问题文本:去除HTML实体、多余空格 function normalizeText(text) { return text .replace(/ /g, ' ') .replace(/&[a-zA-Z0-9#]+;/g, '') .replace(/\s+/g, ' ') .trim() .toLowerCase(); } // 定位并填充单个问题,返回Promise表示处理完成 function setAnswerByKeyword(questionKeyword, answerText) { return new Promise((resolve) => { // 每次重新获取问题容器,确保捕获动态加载的新问题 const questionContainers = document.querySelectorAll('div[data-automation-id="questionItem"]'); for (const container of questionContainers) { // 跳过已处理的容器 if (processedContainers.has(container)) continue; const questionText = normalizeText(container.textContent); if (new RegExp(questionKeyword, "i").test(questionText)) { console.log(`匹配到关键词 "${questionKeyword}" 的问题: ${questionText}`); processedContainers.add(container); // 处理单选按钮 const radioButton = Array.from(container.querySelectorAll('input[type="radio"]')).find( radio => radio.value.toLowerCase() === answerText.toLowerCase() ); if (radioButton) { radioButton.checked = true; // 触发change事件,确保动态内容加载 radioButton.dispatchEvent(new Event('change', { bubbles: true, cancelable: true })); console.log(`单选按钮设置完成: ${answerText}`); // 等待DOM更新后再resolve,给动态加载留时间 requestAnimationFrame(resolve); return; } // 处理文本输入框 const textInput = container.querySelector('input[type="text"][data-automation-id="textInput"], input[data-automation-id="textInput"]'); if (textInput) { // 模拟真实用户输入流程 textInput.focus(); textInput.value = answerText; // 触发input和change事件,确保表单识别输入 textInput.dispatchEvent(new Event('input', { bubbles: true })); textInput.dispatchEvent(new Event('change', { bubbles: true })); console.log(`文本输入框填充完成: ${answerText}`); resolve(); return; } console.warn(`未找到关键词 "${questionKeyword}" 的输入控件`); resolve(); return; } } console.warn(`未找到包含关键词 "${questionKeyword}" 的问题`); resolve(); }); } // 按顺序逐个处理问题,确保动态加载的问题被捕获 async function fillForm() { for (const qa of questionsAndAnswers) { await setAnswerByKeyword(qa.questionKeyword, qa.answerText); // 可选:给动态加载留额外时间,根据表单调整 await new Promise(resolve => setTimeout(resolve, 200)); } console.log("所有问题填充完成"); } // 初始延迟等待表单加载 setTimeout(fillForm, 1000);
关键改进说明
- 串行异步处理:改用
async/await按顺序逐个处理每个问题,确保前一个问题触发的动态内容加载完成后,再处理下一个问题,避免因元素未加载导致的匹配失败 - 已处理容器标记:用
WeakSet记录已处理的问题容器,避免重复关键词匹配到同一个问题 - 优化事件触发:文本输入框去掉固定延迟,改用真实用户的输入事件序列(focus→赋值→input→change),提升表单识别率;单选按钮触发带
cancelable: true的change事件,确保动态逻辑正确执行 - 动态元素重新获取:每次处理问题时重新查询所有问题容器,保证新加载的动态问题被捕获
内容的提问来源于stack exchange,提问作者Datacrawler
相关产品推荐
相关产品推荐

