Tampermonkey自动填充脚本在Payoneer等网站无法自动运行怎么办
问题描述
我编写了若干Tampermonkey脚本,用于访问网站时自动填充用户名、密码并点击登录按钮。在部分网站上,实现逻辑非常简单,代码如下:
document.getElementById('username').value='myname' document.getElementById('loginButton').click()
访问对应网站时上述操作会瞬间自动完成。但在部分网站(例如Payoneer登录页)上,脚本完全不会自动运行:将脚本代码粘贴到浏览器控制台中可以正常执行,但页面加载时不会自动触发。
当前使用的脚本如下:
// ==UserScript== // @name payoneer // @namespace http://tampermonkey.net/ // @version 0.1 // @description try to take over the world! // @author You // @match https://login.payoneer.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=payoneer.com // @grant none // @run-at document-start // ==/UserScript== (function() { window.onload = function (){ function replaceValue(selector, value) { const el = document.querySelector(selector); if (el) { el.focus(); el.select(); if (!document.execCommand('insertText', false, value)) { // Fallback for Firefox: just replace the value el.value = 'new text'; } el.dispatchEvent(new Event('change', {bubbles: true})); // usually not needed } return el; } replaceValue('#username',"myUsername@gmail.com"); document.getElementsByClassName('text-box__input')[1].setAttribute("id","passworde"); replaceValue('#passworde',"MyPASsword123!") } 'use strict'; // Your code here... })();
问题原因
- 脚本设置了
@run-at document-start,运行时机过早,此时页面DOM还未开始渲染。虽然绑定了window.onload事件,但Payoneer登录页是React构建的单页应用,登录表单是在window.onload触发后才通过异步逻辑插入到页面中的,执行填充逻辑时根本找不到目标DOM元素,自然运行无效。 - 直接覆盖
window.onload的事件绑定方式很容易被页面自身的脚本重写,导致绑定的回调函数根本不会执行。 - 填充逻辑的Firefox兼容分支存在bug,固定写死了
el.value = 'new text',不会填入实际的账号密码值。 - 仅触发
change事件无法被React/Vue这类前端框架识别,框架内部维护的表单状态不会同步更新,即使给input赋值了也会被框架后续的渲染逻辑覆盖。
修复方案
调整脚本运行时机,改用DOM监听/轮询的方式等目标表单元素真正渲染完成后再执行填充逻辑,同时修复原有代码的bug,补全框架需要的事件触发。修正后的完整代码如下:
// ==UserScript== // @name payoneer // @namespace http://tampermonkey.net/ // @version 0.2 // @description 自动填充Payoneer登录信息 // @author You // @match https://login.payoneer.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=payoneer.com // @grant none // @run-at document-end // ==/UserScript== (function() { 'use strict'; function replaceValue(selector, value) { const el = document.querySelector(selector); if (!el) return false; el.focus(); el.select(); if (!document.execCommand('insertText', false, value)) { // Firefox兼容逻辑 el.value = value; } // 触发input、change事件,适配前端框架的状态同步 el.dispatchEvent(new Event('input', {bubbles: true})); el.dispatchEvent(new Event('change', {bubbles: true})); el.blur(); return true; } // 轮询检测目标元素是否加载完成 const fillTimer = setInterval(() => { const usernameFilled = replaceValue('#username', "myUsername@gmail.com"); const pwdInput = document.getElementsByClassName('text-box__input')[1]; let passwordFilled = false; if (pwdInput) { pwdInput.id = "passworde"; passwordFilled = replaceValue('#passworde', "MyPASsword123!"); } // 两个字段都填充完成后清除轮询 if (usernameFilled && passwordFilled) { clearInterval(fillTimer); // 需要自动点击登录的话,替换下方选择器为实际登录按钮的选择器,取消注释即可 // document.querySelector('登录按钮选择器').click(); } }, 200); // 10秒后强制停止轮询,避免脚本无限运行 setTimeout(() => clearInterval(fillTimer), 10000); })();
关键调整说明
- 将
@run-at从document-start改为document-end,避免脚本运行过早和页面自身脚本产生冲突。 - 用
setInterval轮询替代window.onload触发逻辑,只要目标表单元素渲染到页面就立刻执行填充,适配单页应用的异步渲染逻辑。如果追求更低的性能消耗,也可以将轮询替换为MutationObserver监听DOM树变化,实现效果一致。 - 补全了
input事件触发,保证React等框架可以正确识别到input值的变更,不会出现赋值后被页面逻辑清空的问题。 - 修复了Firefox兼容分支的bug,现在会正确传入需要填充的账号密码值。
- 弃用直接覆盖
window.onload的绑定方式,避免被页面自身脚本重写导致回调失效。
内容的提问来源于stack exchange,提问作者Randy VU
相关产品推荐
相关产品推荐

