Greasy Fork is available in English.

自动识别填充网页验证码

自动填充网页中出现的图形验证码,如有问题请加群764904163反馈🫡

目前為 2023-02-14 提交的版本,檢視 最新版本

// ==UserScript==
// @name         自动识别填充网页验证码
// @namespace    http://tampermonkey.net/
// @version      0.3.6
// @description  自动填充网页中出现的图形验证码,如有问题请加群764904163反馈🫡
// @author       lcymzzZ
// @license      GPL Licence
// @connect      *
// @match        http://*/*
// @match        https://*/*
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// ==/UserScript==

(function() {
    'use strict';

    var element, input, imgIndex, inputIndex;
    var localRules = [];
    var queryUrl = "http://captcha.zwhyzzz.top:8091/"
    var exist = false;
    var iscors = false;

    //添加菜单
    GM_registerMenuCommand('设置识别速率', setSpeed);
    GM_registerMenuCommand('添加当前页面规则', addRule);
    GM_registerMenuCommand('清除当前页面规则', delRule);
    GM_registerMenuCommand('交流/反馈群:764904163', ()=>{window.open("https://jq.qq.com/?_wv=1027&k=9OATqk9I")});

    GM_setValue("preCode", "");

    function setSpeed(){
        //弹出窗体
        while (true){
            var speed = prompt("请输入识别速率(1-10),默认为3\n注意:\n①数字越大识别越慢,更兼容网络不佳或验证码刷新较慢的情况\n②数字设置过小易导致识别出错", "");
            //点击取消
            if (speed == null) {
                return;
            }
            //输入非法字符
            if (isNaN(speed) || speed < 1 || speed > 10) {
                alert("请输入1—10之间的数字");
                continue;
            }
            GM_setValue("speed", parseInt(speed) * 100);
            alert("识别速率设置成功");
            return;
        }
    }

    //判断是否为验证码(预设规则)
    function isCode(){
        if (element.height >= 100 || element.height == element.width)
            return false;
        var attrList = ["id", "title", "alt", "name", "className", "src", "parentNode.id", "parentNode.className"];
        var strList = ["code", "Code", "CODE", "captcha", "Captcha", "CAPTCHA", "yzm", "Yzm", "YZM", "check", "Check", "CHECK", "random", "Random", "RANDOM", "veri", "Veri", "VERI", "验证码", "看不清", "换一张"];
        for (var i = 0; i < attrList.length; i++) {
            for (var j = 0; j < strList.length; j++) {
                var str = "element." + attrList[i];
                var attr = eval(str);
                if (attr.indexOf(strList[j]) != -1) {
                    return true;
                }
            }
        }
        return false;
    }

    //判断是否为验证码输入框(预设规则)
    function isInput(){
        var attrList = ["placeholder", "alt", "title", "id", "className"];
        var strList = ["code", "Code", "CODE", "captcha", "Captcha", "CAPTCHA", "yzm", "Yzm", "YZM", "check", "Check", "CHECK", "random", "Random", "RANDOM", "veri", "Veri", "VERI", "验证码", "看不清", "换一张"];
        for (var i = 0; i < attrList.length; i++) {
            for (var j = 0; j < strList.length; j++) {
                var str = "input." + attrList[i];
                var attr = eval(str);
                if (attr.indexOf(strList[j]) != -1) {
                    return true;
                }
            }
        }
        return false;
    }

    //手动添加规则(操作)
    function addRule(){
        var ruleData = {"url": window.location.href, "img": "", "input": ""};
        //检测鼠标右键点击事件
        alert("请在验证码图片上点击鼠标“右”键");
        document.oncontextmenu = function(e){
            e = e || window.event;
            var imgList = document.getElementsByTagName('img');
            // console.log(imgList);
            for (var i = 0; i < imgList.length; i++) {
                if (imgList[i] == e.target && imgList[i].tagName == "IMG") {
                    var k = i;
                }
            }
            if (k == null) {
                alert("选择有误,请重新点击验证码图片");
                return;
            }
            ruleData.img = k;
            alert("请在验证码输入框上点击鼠标“左”键");
            document.onclick = function(e){
                e = e || window.event;
                var inputList = document.getElementsByTagName('input');
                // console.log(inputList);
                for (var i = 0; i < inputList.length; i++) {
                    if (inputList[i] == e.target && inputList[i].tagName == "INPUT") {
                        if (inputList[0].id == "_w_simile") {
                            var k = i - 1;
                        }
                        else {
                            var k = i;
                        }
                    }
                }
                if (k == null) {
                    alert("选择有误,请重新点击验证码输入框");
                    return;
                }
                ruleData.input = k;
                // console.log(ruleData);
                addR(ruleData).then((res)=>{
                    if (res.status == 200){
                        alert("添加规则成功");
                        start();
                        //结束事件监听
                        document.oncontextmenu = null;
                        document.onclick = null;
                    }
                    else {
                        alert("Error,添加规则失败");
                        document.oncontextmenu = null;
                        document.onclick = null;
                    }
                });
            }
        }
    }

    //手动添加规则(请求)
    function addR(ruleData){
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: "POST",
                url: queryUrl+"updateRule",
                data: JSON.stringify(ruleData),
                headers: {
                    "Content-Type": "application/json"
                },
                onload: function(response) {
                    return resolve(response);
                }
            });
        });
    }

    //删除当前页面规则
    function delRule(){
        var ruleData = {"url": window.location.href}
        delR(ruleData).then((res)=>{
            if (res.status == 200)
                alert("删除规则成功");
            else
                alert("Error,删除规则失败");
        });
    }

    //删除规则(请求)
    function delR(ruleData){
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: "POST",
                url: queryUrl+"deleteRule",
                data: JSON.stringify(ruleData),
                headers: {
                    "Content-Type": "application/json"
                },
                onload: function(response) {
                    return resolve(response);
                }
            });
        });
    }

    //按已存规则填充
    function codeByRule(){
        var code = "";
        var src = element.src;
        if (src.indexOf('data:image') != -1) {
            // console.log(src);
            code = src.split("base64,")[1];
            GM_setValue("tempCode", code);
                if (GM_getValue("tempCode") != GM_getValue("preCode")) {
                    // console.log("preCode:" + GM_getValue("preCode"))
                    // console.log("tempCode:" + GM_getValue("tempCode"))
                    GM_setValue("preCode", GM_getValue("tempCode"));
                    p1(code).then((ans) => {
                        writeIn1(ans);
                    });
                }
        }
        else {
            setTimeout(function(){
                try {
                    var img = element;
                    var canvas = document.createElement("canvas");
                    var ctx = canvas.getContext("2d");
                    canvas.width = img.width;
                    canvas.height = img.height;
                    ctx.drawImage(img, 0, 0, img.width, img.height);
                    code = canvas.toDataURL("image/png").split("base64,")[1];
                    GM_setValue("tempCode", code);
                    if (GM_getValue("tempCode") != GM_getValue("preCode")) {
                        // console.log("preCode:" + GM_getValue("preCode"))
                        // console.log("tempCode:" + GM_getValue("tempCode"))
                        GM_setValue("preCode", GM_getValue("tempCode"));
                        p1(code).then((ans) => {
                            writeIn1(ans);
                        });
                    }
                }
                catch(err){
                    return;
                }
            }, GM_getValue("speed"));
        }
    }

    //寻找网页中的验证码
    function findCode(k){
        var code = '';
        var codeList = document.getElementsByTagName('img');
        // console.log(codeList);
        for (var i = k; i < codeList.length; i++) {
            var src = codeList[i].src;
            element = codeList[i];
            if (src.indexOf('data:image') != -1) {
                if (isCode()) {
                    code = src.split("base64,")[1];
                    // console.log('code: ' + code);
                    GM_setValue("tempCode", code);
                    if (GM_getValue("tempCode") != GM_getValue("preCode")) {
                        // console.log("preCode:" + GM_getValue("preCode"))
                        // console.log("tempCode:" + GM_getValue("tempCode"))
                        GM_setValue("preCode", GM_getValue("tempCode"));
                        p(code, i).then((ans) => {
                            writeIn(ans);
                        });
                    }
                    break;
                }
            }
            if (src.indexOf('http') != -1 || src.indexOf('https') != -1) {
                if (isCode()) {
                    setTimeout(function(){
                        try {
                            var img = element;
                            var canvas = document.createElement("canvas");
                            var ctx = canvas.getContext("2d");
                            canvas.width = img.width;
                            canvas.height = img.height;
                            ctx.drawImage(img, 0, 0, img.width, img.height);
                            try{
                                code = canvas.toDataURL("image/png").split("base64,")[1];
                            }
                            catch(err){
                                //console.log(err);
                                findCode(i + 1);
                                return;
                            }
                            // console.log(code);
                            GM_setValue("tempCode", code);
                            if (GM_getValue("tempCode") != GM_getValue("preCode")) {
                                iscors = isCORS();
                                // console.log("preCode:" + GM_getValue("preCode"))
                                // console.log("tempCode:" + GM_getValue("tempCode"))
                                GM_setValue("preCode", GM_getValue("tempCode"));
                                p(code, i).then((ans) => {
                                    writeIn(ans);
                                });
                            }
                        }
                        catch(err){
                            return;
                        }
                    }, GM_getValue("speed"));
                    break;
                }
            }
        }
    }

    //寻找网页中的验证码输入框
    function findInput(){
        var inputList = document.getElementsByTagName('input');
        // console.log(inputList);
        for (var i = 0; i < inputList.length; i++) {
            input = inputList[i];
            if (isInput()) {
                return true;
            }
        }
    }

    //将识别结果写入验证码输入框(预设规则)
    function writeIn(ans){
        if (findInput()) {
            ans = ans.replace(/\s+/g,"");
            input.value = ans;
            if (typeof(InputEvent)!=="undefined"){
                input.value = ans;
                input.dispatchEvent(new InputEvent('input'));
                var eventList = ['input', 'change', 'blur', 'focus', 'keypress', 'keyup', 'keydown', 'select'];
                for (var i = 0; i < eventList.length; i++) {
                    fire(input, eventList[i]);
                }
                input.value = ans;
            }
            else if(KeyboardEvent) {
                input.dispatchEvent(new KeyboardEvent("input"));
            }
        }
    }

    //识别验证码(预设规则)
    function p(code, i){
        return new Promise((resolve, reject) =>{
            const datas = {
                "ImageBase64": String(code),
            }
            GM_xmlhttpRequest({
                method: "POST",
                url: "http://captcha.zwhyzzz.top:6688/identify_GeneralCAPTCHA",
                data: JSON.stringify(datas),
                headers: {
                    "Content-Type": "application/json",
                },
                responseType: "json",
                onload: function(response) {
                    // console.log(response);
                    if (response.status == 200) {
                        var result = response.response["result"];
                        console.log("识别结果:" + result);
                        return resolve(result);
                    }
                    else {
                        try {
                            if (response.response["result"] == null)
                                findCode(i + 1);
                            else
                                console.log("识别失败");
                        }
                        catch(err){
                            console.log("识别失败");
                        }
                    }
                }
            });
        });
    }

    //识别验证码(自定义规则)
    function p1(code){
        return new Promise((resolve, reject) =>{
            const datas = {
                "ImageBase64": String(code),
            }
            GM_xmlhttpRequest({
                method: "POST",
                url: "http://captcha.zwhyzzz.top:6688/identify_GeneralCAPTCHA",
                data: JSON.stringify(datas),
                headers: {
                    "Content-Type": "application/json",
                },
                responseType: "json",
                onload: function(response) {
                    // console.log(response);
                    if (response.status == 200) {
                        var result = response.response["result"];
                        console.log("识别结果:" + result);
                        return resolve(result);
                    }
                    else {
                        console.log("识别失败");
                    }
                }
            });
        });
    }

    //判断是否跨域
    function isCORS(){
        try {
            if (element.src.indexOf('http') != -1 || element.src.indexOf('https') != -1) {
                if (element.src.indexOf(window.location.host) == -1) {
                    console.log("检测到当前页面存在跨域问题");
                    return true;
                }
                //console.log("当前页面不存在跨域问题");
                return false;
            }
        }
        catch(err){
            return;
        }
    }

    //将url转换为base64(解决跨域问题)
    function p2(){
        return new Promise((resolve, reject) =>{
            GM_xmlhttpRequest({
                url: element.src,
                method: "GET",
                headers: {'Content-Type': 'application/json; charset=utf-8','path' : window.location.href},
                responseType: "blob",
                onload: function(response) {
                    // console.log(response);
                    let blob = response.response;
                    let reader = new FileReader();
                    reader.onloadend = (e) => {
                        let data = e.target.result;
                        element.src = data;
                        return resolve(data);
                    }
                    reader.readAsDataURL(blob);
                }
            });
        });
    }

    //此段逻辑借鉴Crab大佬的代码,十分感谢
    function fire(element,eventName){
        var event = document.createEvent("HTMLEvents");
        event.initEvent(eventName, true, true);
        element.dispatchEvent(event);
    }

    //将识别结果写入验证码输入框(自定义规则)
    function writeIn1(ans){
        ans = ans.replace(/\s+/g,"");
        input.value = ans;
        if (typeof(InputEvent)!=="undefined"){
            input.value = ans;
            input.dispatchEvent(new InputEvent('input'));
            var eventList = ['input', 'change', 'blur', 'focus', 'keypress', 'keyup', 'keydown', 'select'];
            for (var i = 0; i < eventList.length; i++) {
                fire(input, eventList[i]);
            }
            input.value = ans;
        }
        else if(KeyboardEvent) {
            input.dispatchEvent(new KeyboardEvent("input"));
        }
    }

    //判断当前页面是否存在规则,返回布尔值
    function compareUrl(){
        return new Promise((resolve, reject) => {
            var datas = {"url": window.location.href};
            GM_xmlhttpRequest({
                method: "POST",
                url: queryUrl+"queryRule",
                headers: {
                    "Content-Type": "application/json"
                },
                data: JSON.stringify(datas),
                onload: function(response) {
                    // console.log(response);
                    try {
                        localRules = JSON.parse(response.responseText);
                    }
                    catch(err){
                        localRules = [];
                    }
                    if (localRules.length == 0)
                        return resolve(false);
                    return resolve(true);
                }
            });
        });
    }

    //开始识别
    function start(){
        if (GM_getValue("speed") == undefined) {
            GM_setValue("speed", 300);
        }
        // console.log("识别速度:" + GM_getValue("speed"));
        compareUrl().then((isExist) => {
            if (isExist) {
                exist = true;
                console.log("【自动识别填充验证码】已存在该网站规则");
                imgIndex = localRules["img"];
                inputIndex = localRules["input"];
                element = document.getElementsByTagName('img')[imgIndex];
                // console.log(element.src);
                input = document.getElementsByTagName('input')[inputIndex];
                // console.log(input);
                var inputList = document.getElementsByTagName('input');
                // console.log(inputList);
                if (inputList[0].id == "_w_simile") {
                    inputIndex = parseInt(inputIndex) + 1;
                    input = inputList[inputIndex];
                }
                iscors = isCORS();
                // console.log(input);
                // console.log(element);
                if (iscors) {
                    p2().then(() => {
                        // console.log(data);
                        codeByRule();
                    });
                }
                else {
                    codeByRule();
                }
            }
            else {
                console.log("【自动识别填充验证码】不存在该网站规则,正在根据预设规则自动识别...");
                findCode(0);
            }
        });
    }

    //页面变化执行函数
    function pageChange(){
        if (exist) {
            element = document.getElementsByTagName('img')[imgIndex];
            input = document.getElementsByTagName('input')[inputIndex];
            // console.log(element);
            // console.log(input);
            iscors = isCORS();
            if (iscors) {
                p2().then(() => {
                    // console.log(data);
                    codeByRule();
                });
            }
            else {
                codeByRule();
            }
        }
        else {
            findCode(0);
        }
    }

    console.log("【自动识别填充验证码】正在运行...");

    start();

    var imgSrc = "";
    //监听页面变化
    setTimeout(function(){
        const targetNode = document.body;
        const config = { attributes:true, childList: true, subtree: true};
        const callback = function() {
            try {
                if (iscors){
                    if (element == undefined) {
                        pageChange();
                    }
                    if (element.src != imgSrc) {
                        console.log("【自动识别填充验证码】页面/验证码已更新,正在识别...");
                        imgSrc = element.src;
                        pageChange();
                    }
                }
                else {
                    console.log("【自动识别填充验证码】页面/验证码已更新,正在识别...");
                    pageChange();
                }
            }
            catch(err) {
                return;
                // pageChange();
            }
        }
        const observer = new MutationObserver(callback);
        observer.observe(targetNode, config);
    }, 1000);

})();