// ==UserScript== // @name 自动解析验证码脚本 // @namespace http://tampermonkey.net/ // @version 1.0.2 // @description 自动解析网站验证码并填充 // @author shen chen // @match *://*/* // @grant GM_xmlhttpRequest // @license MIT // @downloadURL none // ==/UserScript== const backUrl = "http://47.98.114.76:81/verification-code"; // 定义一个包含目标网站信息的列表 const siteList = [ { url: "https://zkpt.zj.msa.gov.cn/#/login", // 目标网站URL imageXpath: "//img[@alt='验证码']", // 验证码图片的XPath valueXpath: "//input[@placeholder='图片验证码']" // 验证码输入框的XPath }, { url: "http://10.30.10.42:9080/user/login?redirect=%2F", imageXpath: "//div[@class='ant-col ant-col-8']//img[1]", valueXpath: "(//input[@class='ant-input ant-input-lg'])[3]" }, { url: "http://121.41.173.27:9080/user/login", imageXpath: "//div[@class='ant-col ant-col-8']//img[1]", valueXpath: "(//input[@class='ant-input ant-input-lg'])[3]" }, { url: "https://hhly.chinabeston.com:4443/login/#/login/iev", imageXpath: "//div[@class='el-col el-col-8']//img[1]", valueXpath: "//input[@placeholder='请输入验证码']" }, // 可以添加更多网站配置 ]; /** * 根据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} imageElement - 图片元素 * @param {function} callback - 回调函数,返回Base64字符串 */ function getCaptchaImageAsBase64(img, callback) { img.crossOrigin = 'Anonymous'; // 处理跨域问题 img.onload = function () { const canvas = document.createElement('canvas'); canvas.width = 120; canvas.height = 40; // console.log('图片尺寸:', img.width, img.height) const ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0); // 获取Base64编码 const dataURL = canvas.toDataURL('image/png'); // console.log('Base64编码:',dataURL); callback(dataURL); }; img.onerror = function () { console.error('图片加载失败'); callback(null); }; } /** * 发送验证码图片到后端接口并填充解析结果 * @param {string} base64Image - 验证码图片的URL * @param {string} valueXpath - 验证码输入框的XPath */ function sendCaptchaToBackend(base64Image, valueXpath) { // console.log("发送验证码图片到后端接口:"); 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) { // console.log("验证码解析成功:", data.captcha_value); // 自动填写验证码到输入框 const captchaInput = getElementByXpath(valueXpath); if (captchaInput) { captchaInput.value = data.captcha_value; // console.log("验证码已自动填写"); } else { console.error("未找到验证码输入框"); } } else { console.error("验证码解析失败:", data.error || "未知错误"); } }, onerror: function (error) { console.error("请求后端失败:", error); } }); } /** * 根据XPath获取异步加载的DOM元素 * @param {string} xpath - XPath表达式 * @param {number} timeout - 超时时间(毫秒),默认5000ms * @returns {Promise} - 匹配到的元素或null */ function waitForElementByXpath(xpath, timeout = 5000) { return new Promise((resolve, reject) => { const startTime = Date.now(); // 使用 MutationObserver 监听 DOM 变化 const observer = new MutationObserver(() => { const element = getElementByXpath(xpath); if (element) { observer.disconnect(); // 停止观察 resolve(element); } else if (Date.now() - startTime > timeout) { observer.disconnect(); // 超时后停止观察 reject(new Error("超时未找到元素")); } }); // 开始观察整个文档的变化 observer.observe(document.body, {childList: true, subtree: true}); // 如果超时仍未找到元素,拒绝 Promise setTimeout(() => { observer.disconnect(); reject(new Error("超时未找到元素")); }, timeout); }); } (function () { 'use strict'; // 检查当前网站是否在列表中 const currentUrl = window.location.href; const siteConfig = siteList.find(site => currentUrl.includes(site.url)); if (!siteConfig) { console.log("当前网站不在目标列表中"); return; } console.log("匹配到目标网站:", siteConfig.url); // 获取验证码图片元素 waitForElementByXpath(siteConfig.imageXpath) .then((element) => { // console.log("找到元素:", element); if (!element) { console.error("未找到验证码图片元素"); return; } // 获取图片的二进制数据(Base64编码) getCaptchaImageAsBase64(element, (base64Image) => { if (base64Image) { // console.log("成功获取验证码图片的Base64编码"); // 发送验证码图片到后端接口进行解析 sendCaptchaToBackend(base64Image, siteConfig.valueXpath); } else { console.error("无法获取验证码图片的Base64编码"); } }); }).catch((error) => { console.error(error.message); }); })();