// ==UserScript== // @name 自动识别填充网页验证码 // @namespace http://tampermonkey.net/ // @version 0.4.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, canvasIndex, inputIndex; var localRules = []; var queryUrl = "http://captcha.zwhyzzz.top:8092/" var exist = false; var iscors = false; var inBlack = false; var firstin = true; //添加菜单 GM_registerMenuCommand('添加当前页面规则', addRule); GM_registerMenuCommand('清除当前页面规则', delRule); GM_registerMenuCommand('管理网页黑名单', manageBlackList); GM_registerMenuCommand('交流/反馈群:764904163', ()=>{window.open("https://jq.qq.com/?_wv=1027&k=9OATqk9I")}); GM_setValue("preCode", ""); //判断是否为验证码(预设规则) function isCode(){ if (element.height >= 100 || element.height == element.width) return false; var attrList = ["id", "title", "alt", "name", "className", "src"]; 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 = element[attrList[i]]; if (attr.indexOf(strList[j]) != -1) { return true; } } } return false; } //判断是否为验证码输入框(预设规则) function isInput(){ var attrList = ["placeholder", "alt", "title", "id", "className", "name"]; 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 = input[attrList[i]]; if (attr.indexOf(strList[j]) != -1) { return true; } } } return false; } //手动添加规则(操作) function addRule(){ var ruleData = {"url": window.location.href.split("?")[0], "img": "", "input": "", "type": ""}; //检测鼠标右键点击事件 alert("请在验证码图片上点击鼠标“右”键"); document.oncontextmenu = function(e){ e = e || window.event; e.preventDefault(); //如果e.target是img标签,则返回img标签的index,如果是canvas标签,则返回canvas标签的index if (e.target.tagName == "IMG" || e.target.tagName == "GIF") { var imgList = document.getElementsByTagName('img'); for (var i = 0; i < imgList.length; i++) { if (imgList[i] == e.target) { var k = i; ruleData.type = "img"; } } } else if (e.target.tagName == "CANVAS") { var imgList = document.getElementsByTagName('canvas'); for (var i = 0; i < imgList.length; i++) { if (imgList[i] == e.target) { var k = i; ruleData.type = "canvas"; } } } if (k == null) { alert("选择有误,请重新点击验证码图片"); return; } ruleData.img = k; alert("请在验证码输入框上点击鼠标“左”键"); document.onclick = function(e){ e = e || window.event; e.preventDefault(); 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] && 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.split("?")[0]} 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 (firstin){ firstin = false; 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 { try { var img = element; if (img.src && img.width != 0 && img.height != 0) { 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) => { if (ans != "") writeIn1(ans); else codeByRule(); }); } } else { codeByRule(); } } catch(err){ return; } } } else { 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 { var canvas = document.createElement("canvas"); var ctx = canvas.getContext("2d"); element.onload = function() { // console.log("img.onload"); canvas.width = element.width; canvas.height = element.height; ctx.drawImage(element, 0, 0, element.width, element.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); }); } } } } } function canvasRule(){ setTimeout(function(){ // console.log(element.toDataURL("image/png")); try { var code = element.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){ canvasRule(); } }, 100); } //寻找网页中的验证码 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()) { firstin = false; 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; } } else { if (isCode()) { if (firstin){ firstin = false; var img = element; if (img.src && img.width != 0 && img.height != 0) { 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]; 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) => { if (ans != "") writeIn(ans); else findCode(i); }); return; } } else{ findCode(i); return; } } else { var canvas = document.createElement("canvas"); var ctx = canvas.getContext("2d"); element.onload = function(){ canvas.width = element.width; canvas.height = element.height; ctx.drawImage(element, 0, 0, element.width, element.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); }); return; } } 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: queryUrl + "identify_GeneralCAPTCHA", data: JSON.stringify(datas), headers: { "Content-Type": "application/json", }, responseType: "json", onload: function(response) { //console.log(response); if (response.status == 200) { try{ var result = response.response["result"]; console.log("识别结果:" + result); return resolve(result); } catch(e){ if (response.responseText.indexOf("接口请求频率过高") != -1) // console.log(response.responseText) topNotice(response.responseText); } } 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: queryUrl + "identify_GeneralCAPTCHA", data: JSON.stringify(datas), headers: { "Content-Type": "application/json", }, responseType: "json", onload: function(response) { // console.log(response); if (response.status == 200) { try{ var result = response.response["result"]; console.log("识别结果:" + result); return resolve(result); } catch(e){ if (response.responseText.indexOf("接口请求频率过高") != -1) // console.log(response.responseText) topNotice(response.responseText); } } 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(){ compareUrl().then((isExist) => { if (isExist) { exist = true; console.log("【自动识别填充验证码】已存在该网站规则"); if (localRules["type"] == "img" || localRules["type"] == null) { 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] && inputList[0].id == "_w_simile") { inputIndex = parseInt(inputIndex) + 1; input = inputList[inputIndex]; } if (element && input) { iscors = isCORS(); // console.log(input); // console.log(element); if (iscors) { p2().then(() => { // console.log(data); codeByRule(); }); } else { codeByRule(); } } else pageChange(); } else if (localRules["type"] == "canvas") { canvasIndex = localRules["img"]; inputIndex = localRules["input"]; element = document.getElementsByTagName('canvas')[canvasIndex]; input = document.getElementsByTagName('input')[inputIndex]; var inputList = document.getElementsByTagName('input'); // console.log(inputList); if (inputList[0] && inputList[0].id == "_w_simile") { inputIndex = parseInt(inputIndex) + 1; input = inputList[inputIndex]; } iscors = isCORS(); if (iscors) { p2().then(() => { // console.log(data); canvasRule(); }); } else { canvasRule(); } } } else { console.log("【自动识别填充验证码】不存在该网站规则,正在根据预设规则自动识别..."); findCode(0); } }); } //页面变化执行函数 function pageChange(){ if (exist) { if (localRules["type"] == "img" || localRules["type"] == null) { element = document.getElementsByTagName('img')[imgIndex]; input = document.getElementsByTagName('input')[inputIndex]; var inputList = document.getElementsByTagName('input'); // console.log(inputList); if (inputList[0] && inputList[0].id == "_w_simile") { inputIndex = parseInt(inputIndex) + 1; input = inputList[inputIndex]; } // console.log(element); // console.log(input); iscors = isCORS(); if (iscors) { p2().then(() => { // console.log(data); codeByRule(); }); } else { codeByRule(); } } else if (localRules["type"] == "canvas") { element = document.getElementsByTagName('canvas')[canvasIndex]; input = document.getElementsByTagName('input')[inputIndex]; var inputList = document.getElementsByTagName('input'); // console.log(inputList); if (inputList[0] && inputList[0].id == "_w_simile") { inputIndex = parseInt(inputIndex) + 1; input = inputList[inputIndex]; } // console.log(element); // console.log(input); iscors = isCORS(); if (iscors) { p2().then(() => { // console.log(data); canvasRule(); }); } else { canvasRule(); } } } else { findCode(0); } } function topNotice(msg){ var div = document.createElement('div'); div.style.position = 'fixed'; div.style.top = '0'; div.style.left = '0'; div.style.width = '100%'; div.style.height = '5%'; div.style.zIndex = '999999'; div.style.background = 'rgba(0,0,0,0.5)'; div.style.display = 'flex'; div.style.justifyContent = 'center'; div.style.alignItems = 'center'; div.style.color = '#fff'; div.style.fontFamily = 'Microsoft YaHei'; div.style.textAlign = 'center'; div.innerHTML = msg; document.body.appendChild(div); setTimeout(function(){ document.body.removeChild(div); }, 2500); } function manageBlackList(){ var blackList = GM_getValue("blackList", []); var div = document.createElement("div"); div.style.width = "700px"; div.style.height = "350px"; div.style.position = "fixed"; div.style.top = "50%"; div.style.left = "50%"; div.style.transform = "translate(-50%, -50%)"; div.style.backgroundColor = "white"; div.style.border = "1px solid black"; div.style.zIndex = "999999"; div.style.textAlign = "center"; div.style.paddingTop = "20px"; div.style.paddingBottom = "20px"; div.style.paddingLeft = "20px"; div.style.paddingRight = "20px"; div.style.boxShadow = "0px 0px 10px 0px rgba(0,0,0,0.75)"; div.style.borderRadius = "10px"; div.style.overflow = "auto"; div.innerHTML = "

网页黑名单

网址操作
"; document.body.insertBefore(div, document.body.firstChild); var table = document.getElementById("blackList").getElementsByTagName('tbody')[0]; for (var i = 0; i < blackList.length; i++) { var row = table.insertRow(i); row.insertCell(0).innerHTML = "
" + blackList[i] + "
"; var removeBtn = document.createElement("button"); removeBtn.className = "remove"; removeBtn.style.backgroundColor = "transparent"; removeBtn.style.color = "blue"; removeBtn.style.border = "none"; removeBtn.style.padding = "5px"; removeBtn.style.fontSize = "14px"; removeBtn.style.borderRadius = "5px"; removeBtn.innerText = "移除"; row.insertCell(1).appendChild(removeBtn); } var close = document.getElementById("close"); close.onclick = function(){ div.remove(); } var add = document.getElementById("add"); add.onclick = function(){ var cf = confirm("黑名单中的网页将不会自动识别验证码\n确定要将当前页面加入黑名单吗?"); if (cf == true) { var blackList = GM_getValue("blackList", []); var url = window.location.href.split("?")[0]; if (blackList.indexOf(url) == -1) { blackList.push(url); GM_setValue("blackList", blackList); var row = table.insertRow(table.rows.length); row.insertCell(0).innerHTML = "
" + url + "
"; var removeBtn = document.createElement("button"); removeBtn.className = "remove"; removeBtn.style.backgroundColor = "transparent"; removeBtn.style.color = "blue"; removeBtn.style.border = "none"; removeBtn.style.padding = "5px"; removeBtn.style.fontSize = "14px"; removeBtn.style.borderRadius = "5px"; removeBtn.innerText = "移除"; row.insertCell(1).appendChild(removeBtn); removeBtn.onclick = function(){ var index = this.parentNode.parentNode.rowIndex - 1; blackList.splice(index, 1); GM_setValue("blackList", blackList); this.parentNode.parentNode.remove(); } topNotice("添加黑名单成功,刷新页面生效") } else { topNotice("该网页已在黑名单中"); } } else { return; } } var remove = document.getElementsByClassName("remove"); for (var i = 0; i < remove.length; i++) { remove[i].onclick = function(){ var index = this.parentNode.parentNode.rowIndex - 1; blackList.splice(index, 1); GM_setValue("blackList", blackList); this.parentNode.parentNode.remove(); topNotice("移除黑名单成功,刷新页面生效"); } } } console.log("【自动识别填充验证码】正在运行..."); //检查黑名单 var blackList = GM_getValue("blackList", []); var url = window.location.href.split("?")[0]; if (blackList.indexOf(url) != -1) { console.log("【自动识别填充验证码】当前页面在黑名单中"); inBlack = true; return; } else start(); var imgSrc = ""; //监听页面变化 setTimeout(function(){ const targetNode = document.body; const config = { attributes:true, childList: true, subtree: true}; const callback = function() { if (inBlack) return; 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); //监听元素,比较canvas.toDataUrl后的值是否发生变化 setTimeout(function(){ if (inBlack) return; try { if (element.tagName != "CANVAS") return; } catch(err) { return; } var canvasData1 = element.toDataURL(); setInterval(function(){ var canvasData2 = element.toDataURL(); if (canvasData1 != canvasData2) { console.log("【自动识别填充验证码】页面/验证码已更新,正在识别..."); canvasData1 = canvasData2; pageChange(); } }, 0); }, 1000); })();