// ==UserScript== // @name 自动识别填充网页验证码 // @namespace http://tampermonkey.net/ // @version 0.3.5 // @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; } 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 { element.click(); 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((data) => { // console.log(data); codeByRule(data); }); } 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); })();