Tampermonkey设置input值后无法提交表单,如何模拟用户输入触发验证?
解决Human Benchmark数字记忆测试脚本自动提交问题
问题描述
我用Tampermonkey写脚本给Human Benchmark的数字记忆测试作弊,已经能提取需要记忆的数字,用inputElement.value = answerString把答案填入输入框,但必须手动在输入框里改一个字符才能提交,直接提交表单会导致页面重置——网站应该是用JS处理提交逻辑的。想找纯JS的方法,不用手动操作就能让网站认可输入并完成提交。
我的脚本代码(记忆阶段按Enter生效):
// ==UserScript== // @name Human Benchmark Cheat // @namespace http://tampermonkey.net/ // @version 2024-02-04 // @description This script helps cheat on the Number Memory test on Human Benchmark by automatically entering the number you need to remember. // @author Caleb // @match https://humanbenchmark.com/tests/number-memory // @icon https://humanbenchmark.com/favicon.ico // @grant none // ==/UserScript== (function() { 'use strict'; // Listen for keypress events on the page let numberToRemember = ''; document.addEventListener('keypress', function(event) { // If the Enter key is pressed, start the cheat if (event.key === 'Enter') { startCheat(); } }); // Click the button to start the test function pressButton() { // Find and click the button const button = document.querySelector('.css-de05nr.e19owgy710'); button.click(); } // Extracts and stores the number to remember function saveNumber() { // Find the element displaying the number var elements = document.querySelectorAll('.big-number'); // Combine the text content of these elements into a single string numberToRemember = Array.from(elements).map(function(element) { return element.textContent; }).join(''); // Log the number to the console for reference console.log(numberToRemember); } // Put the remembered number into the input field function typeString() { // Find the input field var inputElement = document.querySelector('input'); // Set the value of the input field to the remembered number inputElement.value = numberToRemember; } // Starts the cheat function startCheat() { // Define the class name of the element to monitor const className = 'number-timer-bar'; // Find the element with the specified class name const elementWithClass = document.querySelector(`.${className}`); // Create an observer to detect when the number appears or disappears const observer = new IntersectionObserver(entries => { // Check if the element with the specified class is visible if (entries[0].isIntersecting) { // The number is visible, save it console.log(`Element with class '${className}' is visible!`); saveNumber(); } else { // The number is not visible, paste the answer and submit console.log(`Element with class '${className}' is not visible!`); typeString(); pressButton(); } }); // Start observing the element with the specified class name observer.observe(elementWithClass); } })();
解决方案
问题核心是:直接设置input.value不会触发网站监听的用户输入事件,网站靠这些事件判断输入是否有效。另外提交时要确保网站的JS逻辑能识别输入已完成。
1. 触发输入框的用户输入事件
修改typeString函数,设置值后手动触发input和change事件,模拟真实输入:
function typeString() { const inputElement = document.querySelector('input'); if (!inputElement) return; inputElement.value = numberToRemember; // 触发input事件(网站常用这个监听输入变化) inputElement.dispatchEvent(new Event('input', { bubbles: true })); // 触发change事件,确保表单状态更新 inputElement.dispatchEvent(new Event('change', { bubbles: true })); }
2. 调整提交时机
输入事件需要一点延迟才能被网站处理,可在调用typeString后加短延迟再点击按钮:
// 在startCheat的else分支里修改 else { console.log(`Element with class '${className}' is not visible!`); typeString(); // 延迟100ms再提交,给网站时间处理输入事件 setTimeout(pressButton, 100); }
3. 备选:模拟按键输入(更贴近真实操作)
如果上面的方法无效,可以逐个字符模拟按键输入,完全模拟用户打字:
function typeString() { const inputElement = document.querySelector('input'); if (!inputElement) return; inputElement.focus(); // 先聚焦输入框 inputElement.value = ''; // 清空原有内容 // 逐个字符触发输入事件 for (let i = 0; i < numberToRemember.length; i++) { const char = numberToRemember[i]; setTimeout(() => { inputElement.value += char; inputElement.dispatchEvent(new Event('input', { bubbles: true })); // 可选:模拟完整按键事件链 inputElement.dispatchEvent(new KeyboardEvent('keydown', { key: char })); inputElement.dispatchEvent(new KeyboardEvent('keypress', { key: char })); inputElement.dispatchEvent(new KeyboardEvent('keyup', { key: char })); }, 50 * i); // 每个字符间隔50ms,更像真实打字 } // 所有字符输入完成后再提交 setTimeout(pressButton, 50 * numberToRemember.length); }
修改后的完整脚本
// ==UserScript== // @name Human Benchmark Cheat // @namespace http://tampermonkey.net/ // @version 2024-02-04 // @description 自动完成Human Benchmark数字记忆测试 // @author Caleb // @match https://humanbenchmark.com/tests/number-memory // @icon https://humanbenchmark.com/favicon.ico // @grant none // ==/UserScript== (function() { 'use strict'; let numberToRemember = ''; document.addEventListener('keypress', function(event) { if (event.key === 'Enter') { startCheat(); } }); function pressButton() { const button = document.querySelector('.css-de05nr.e19owgy710'); if (button) button.click(); } function saveNumber() { const elements = document.querySelectorAll('.big-number'); numberToRemember = Array.from(elements).map(el => el.textContent).join(''); console.log('记住的数字:', numberToRemember); } function typeString() { const inputElement = document.querySelector('input'); if (!inputElement) return; inputElement.value = numberToRemember; inputElement.dispatchEvent(new Event('input', { bubbles: true })); inputElement.dispatchEvent(new Event('change', { bubbles: true })); } function startCheat() { const className = 'number-timer-bar'; const elementWithClass = document.querySelector(`.${className}`); if (!elementWithClass) return; const observer = new IntersectionObserver(entries => { if (entries[0].isIntersecting) { console.log('数字显示中,保存数字'); saveNumber(); } else { console.log('数字已隐藏,填入答案'); typeString(); setTimeout(pressButton, 100); } }); observer.observe(elementWithClass); } })();
原理说明
- 网站通常通过监听
input或change事件来更新表单的有效性状态,直接设置value不会触发这些事件,所以需要手动派发。 - 短延迟是为了给网站的JS逻辑留出处理输入的时间,避免点击提交时输入还没被识别。
- 模拟按键输入是最接近真实用户操作的方式,几乎能绕过所有前端的输入验证逻辑。
内容的提问来源于stack exchange,提问作者Caleb
相关产品推荐
相关产品推荐

