Greasy Fork

Greasy Fork is available in English.

自动解析验证码脚本

自动解析网站验证码并填充

当前为 2025-04-16 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         自动解析验证码脚本
// @namespace    http://tampermonkey.net/
// @version      1.0.0
// @description  自动解析网站验证码并填充
// @author       shen chen
// @match        *://*/*
// @grant        GM_xmlhttpRequest
// @license MIT
// ==/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]"
    },
    // 可以添加更多网站配置

];

/**
 * 根据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<HTMLElement|null>} - 匹配到的元素或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);
    });

})();