您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
自动填充网站的用户名密码/验证码 , 以及点击登录按钮
// ==UserScript== // @name 网站自动登录脚本 // @run-at document-end // @namespace http://tampermonkey.net/ // @version 2.0.0 // @description 自动填充网站的用户名密码/验证码 , 以及点击登录按钮 // @author shen chen // @match *://*/* // @grant GM_xmlhttpRequest // @license MIT // ==/UserScript== const backUrl = "http://47.98.114.76:81/verification-code"; // 点击登录按钮等待时间 (不包含验证码) const clickOnlyBtnTime = 1000 // 点击登录按钮等待时间 (包含验证码) const clickBtnTime = 2000 /** * url - 登录页面的URL 必填 * imageXpath - 验证码图片的XPath 如果不填, 则不处理验证码 * valueXpath - 验证码输入框的XPath * loginNameXpath - 登录名输入框的XPath * pwdXpath - 密码输入框的XPath * valueXpath - 验证码输入框的XPath * submitXpath - 提交按钮的XPath * username - 登录名 * password - 密码 * onlySubmit - 是否只处理提交按钮 不处理 用户名/密码/验证码 (不填, 默认 false) * * 1. 如果只需要点击登录按钮, 则 onlySubmit 为 true, 并只需要填写 url 就可以 比如 * { * url: "http://121.41.222.11:9082/user/login", * onlySubmit: false * } * 2. 也可以只填写验证码 * { * url: "https://hhly.chinabeston.com:4443/login/#/login/iev", * imageXpath: "//div[@class='el-col el-col-8']//img[1]", * valueXpath: "//input[@placeholder='请输入验证码']" * }, * 3. 以及所有都需要填写 (用户名/密码/验证码) * { * url: "http://10.30.10.77:9080/user/login", * imageXpath: "//div[@class='ant-col ant-col-8']//img[1]", * loginNameXpath: "//input[@placeholder='请输入帐户名']", * pwdXpath: "//input[@placeholder='密码']", * valueXpath: "(//input[@class='ant-input ant-input-lg'])[3]", * submitXpath: "//button[@type='submit']", * username: "xxxx", * password: "xxxxx", * onlySubmit: false * } * */ const siteList = [ { url: "http://121.41.222.11:9082/user/login", onlySubmit: false }, { url: "https://hhly.chinabeston.com:4443/login/#/login/iev", imageXpath: "//div[@class='el-col el-col-8']//img[1]", valueXpath: "//input[@placeholder='请输入验证码']" }, { url: "http://10.30.10.77:9080/user/login", imageXpath: "//div[@class='ant-col ant-col-8']//img[1]", loginNameXpath: "//input[@placeholder='请输入帐户名']", pwdXpath: "//input[@placeholder='密码']", valueXpath: "(//input[@class='ant-input ant-input-lg'])[3]", submitXpath: "//button[@type='submit']", username: "xxxx", password: "xxxxx", onlySubmit: false } ] (function () { 'use strict'; const currentUrl = window.location.href; const siteConfig = siteList.find(site => currentUrl.includes(site.url)); console.log(`当前页面:${currentUrl}`) if (!siteConfig) return console.log("匹配到目标网站:", siteConfig.url); // 使用DOMContentLoaded事件而不是load事件 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => handler(siteConfig)); } else { handler(siteConfig); } })(); /** * 主处理函数 */ function handler(siteConfig) { console.log('handler') // 使用MutationObserver确保DOM完全加载 const observer = new MutationObserver((mutations, obs) => { console.log('DOM完全加载') if (siteConfig.onlySubmit) { console.log('只处理提交按钮') obs.disconnect(); // 停止观察 setTimeout(() => { clickSubmitBtn(siteConfig); }, clickOnlyBtnTime) return; } if (siteConfig.loginNameXpath) { const loginNameInput = getElementByXpath(siteConfig.loginNameXpath); if (!(loginNameInput)) { console.log('元素未找到,停止观察') obs.disconnect(); // 停止观察 return; } obs.disconnect(); // 停止观察 console.log('处理用户名输入'); inputInput(loginNameInput, siteConfig.username) } if (siteConfig.pwdXpath) { console.log('处理密码输入') const pwdInput = getElementByXpath(siteConfig.pwdXpath); inputInput(pwdInput, siteConfig.password) } if (siteConfig.imageXpath) { console.log('处理验证码输入') const captchaImg = getElementByXpath(siteConfig.imageXpath); if (!captchaImg) { console.log('元素未找到,停止观察') obs.disconnect(); // 停止观察 return } handlerCaptcha(siteConfig, captchaImg); } setTimeout(() => { console.log('处理提交按钮') clickSubmitBtn(siteConfig); }, clickBtnTime) }); // 开始观察DOM变化 observer.observe(document.body, { childList: true, subtree: true, attributes: true }); } /** * 根据XPath获取DOM元素 * @param {string} xpath - XPath表达式 * @returns {HTMLElement|null} - 匹配到的元素或null */ function getElementByXpath(xpath) { const result = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); return result.singleNodeValue; } /** * 将图片元素转换为Base64编码 * @param {HTMLImageElement} img - 图片元素 * @param {function} callback - 回调函数,返回Base64字符串 */ function getCaptchaImageAsBase64(img, callback) { const canvas = document.createElement('canvas'); canvas.width = img.width || 120; canvas.height = img.height || 40; const ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0); const dataURL = canvas.toDataURL('image/png'); callback(dataURL); } /** * 发送验证码图片到后端接口并填充解析结果 * @param {string} base64Image - 验证码图片的URL * @param {string} valueXpath - 验证码输入框的XPath */ function sendCaptchaToBackend(base64Image, valueXpath) { GM_xmlhttpRequest({ method: "POST", url: backUrl, headers: { "Content-Type": "application/json" }, data: JSON.stringify({image_base64: base64Image}), onload: function (response) { const data = JSON.parse(response.responseText); if (data.captcha_value) { const captchaInput = getElementByXpath(valueXpath); inputInput(captchaInput, data.captcha_value) } } }); } function inputInput(element, value) { // focus->input->blur if (!element) { console.log('元素未找到,返回') return } // console.log(`value: ${value}`); var focusEvent = new Event('focus'); element.dispatchEvent(focusEvent); element.value = value; var inputEvent = new Event('input'); element.dispatchEvent(inputEvent); var blurEvent = new Event('blur'); element.dispatchEvent(blurEvent); } function handlerCaptcha(siteConfig, captchaImg) { const valueInput = getElementByXpath(siteConfig.valueXpath); if (valueInput) valueInput.click(); // 确保图片已加载 setTimeout(() => { if (captchaImg.complete) { getCaptchaImageAsBase64(captchaImg, (base64) => { if (base64) sendCaptchaToBackend(base64, siteConfig.valueXpath); }); } else { captchaImg.onload = () => { getCaptchaImageAsBase64(captchaImg, (base64) => { if (base64) sendCaptchaToBackend(base64, siteConfig.valueXpath); }); }; } }, 300) } function clickSubmitBtn(siteConfig) { const submitBtn = getElementByXpath(siteConfig.submitXpath); if (!submitBtn) return submitBtn.click(); }