// ==UserScript==
// @name 自动识别填充网页验证码并提交
// @namespace http://tampermonkey.net/
// @version 0.0.1
// @description 自动填充网页中出现的图形验证码
// @author wupx
// @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, captchaType;
var localRules = [];
var queryUrl = "http://captcha.zwhyzzz.top:8092/"
var exist = false;
var iscors = false;
var inBlack = false;
var firstin = true;
//添加菜单
//GM_registerMenuCommand('管理网页黑名单', manageBlackList);
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 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"));
p(code).then((ans) => {
writeIn1(ans);
});
}
}
catch(err){
canvasRule();
}
}, 100);
}
//寻找网页中的验证码
function findCode(k){
var code = '';
var codeList = document.getElementsByTagName('img');
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];
GM_setValue("tempCode", code);
if (GM_getValue("tempCode") != GM_getValue("preCode")) {
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){
findCode(i + 1);
return;
}
GM_setValue("tempCode", code);
if (GM_getValue("tempCode") != GM_getValue("preCode")) {
iscors = isCORS();
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){
findCode(i + 1);
return;
}
GM_setValue("tempCode", code);
if (GM_getValue("tempCode") != GM_getValue("preCode")) {
iscors = isCORS();
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 findButton(){
var button = document.getElementById('verify-captcha-code-submit');
console.log(button);
button.click();
}
//将识别结果写入验证码输入框(预设规则)
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', '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"));
}
findButton();
}
}
//识别验证码(预设规则)
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) {
if (response.status == 200) {
if (response.responseText.indexOf("触发限流策略") != -1){
topNotice(response.response["msg"]);
}
try{
var result = response.response["result"];
console.log("识别结果:" + result);
return resolve(result);
}
catch(e){
if (response.responseText.indexOf("接口请求频率过高") != -1){
topNotice(response.responseText);
}
}
}
else {
try {
if (response.response["result"] == null){
findCode(i + 1);
}
else{
console.log("识别失败");
}
}
catch(err){
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 FireForReact(element, eventName) {
try {
let env = new Event(eventName);
element.dispatchEvent(env);
var funName = Object.keys(element).find(p => Object.keys(element[p]).find(f => f.toLowerCase().endsWith(eventName)));
if (funName != undefined) {
element[funName].onChange(env)
}
}
catch (e) {}
}
//将识别结果写入验证码输入框(自定义规则)
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', 'focus', 'keypress', 'keyup', 'keydown', 'select'];
for (var i = 0; i < eventList.length; i++) {
fire(input, eventList[i]);
}
FireForReact(input, 'change');
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") {
captchaType = localRules["captchaType"];
imgIndex = localRules["img"];
inputIndex = localRules["input"];
element = document.getElementsByTagName('img')[imgIndex];
input = document.getElementsByTagName('input')[inputIndex];
var inputList = document.getElementsByTagName('input');
if (inputList[0] && inputList[0].id == "_w_simile") {
inputIndex = parseInt(inputIndex) + 1;
input = inputList[inputIndex];
}
if (element && input) {
iscors = isCORS();
if (iscors) {
p2().then(() => {
codeByRule();
});
}
else {
codeByRule();
}
}
else
pageChange();
}
else if (localRules["type"] == "canvas") {
captchaType = localRules["captchaType"];
canvasIndex = localRules["img"];
inputIndex = localRules["input"];
element = document.getElementsByTagName('canvas')[canvasIndex];
input = document.getElementsByTagName('input')[inputIndex];
var inputList = document.getElementsByTagName('input');
if (inputList[0] && inputList[0].id == "_w_simile") {
inputIndex = parseInt(inputIndex) + 1;
input = inputList[inputIndex];
}
iscors = isCORS();
if (iscors) {
p2().then(() => {
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.id = 'topNotice';
div.style.cssText = 'position: fixed; top: 0; left: 0; width: 100%; height: 5%; z-index: 9999999999; background: rgba(117,140,148,1); display: flex; justify-content: center; align-items: center; color: #fff; font-family: "Microsoft YaHei"; text-align: center;';
div.innerHTML = msg;
div.style.fontSize = 'medium';
document.body.appendChild(div);
setTimeout(function(){
document.body.removeChild(document.getElementById('topNotice'));
}, 3500);
}
function manageBlackList(){
var blackList = GM_getValue("blackList", []);
var div = document.createElement("div");
div.style.cssText = 'width: 700px; height: 350px; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: white; border: 1px solid black; z-index: 9999999999; text-align: center; padding-top: 20px; padding-bottom: 20px; padding-left: 20px; padding-right: 20px; box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.75); border-radius: 10px; overflow: auto;';
div.innerHTML = "<h3 style='margin-bottom: 12px; font-weight: bold; font-size: 18px;'>网页黑名单</h3><button style='position: absolute; top: 10px; left: 10px; width: 100px; height: 30px; line-height: 30px; text-align: center; font-size: 13px; margin: 10px' id='add'>添加当前页面</button><table id='blackList' style='width:100%; border-collapse:collapse; border: 1px solid black;'><thead style='background-color: #f5f5f5;'><tr><th style='width: 80%; text-align: center; padding: 5px;'>网址</th><th style='width: 20%; text-align: center; padding: 5px;'>操作</th></tr></thead><tbody></tbody></table><button style='position: absolute; top: 10px; right: 10px; width: 30px; height: 30px; line-height: 30px; text-align: center; font-size: 18px; font-weight: bold; color: #333; background-color: transparent; border: none; outline: none; cursor: pointer;' id='close'>×</button>";
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 = "<div style='white-space: nowrap; overflow: hidden; text-overflow: ellipsis;'>" + blackList[i] + "</div>";
var removeBtn = document.createElement("button");
removeBtn.className = "remove";
removeBtn.style.cssText = 'background-color: transparent; color: blue; border: none; padding: 5px; font-size: 14px; border-radius: 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 = "<div style='white-space: nowrap; overflow: hidden; text-overflow: ellipsis;'>" + url + "</div>";
var removeBtn = document.createElement("button");
removeBtn.className = "remove";
removeBtn.style.cssText = "background-color: transparent; color: blue; border: none; padding: 5px; font-size: 14px; border-radius: 5px; cursor: pointer; ";
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变化
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);
//监听url变化
setTimeout(function(){
if (inBlack) return;
var tempUrl = window.location.href;
setInterval(function(){
if (tempUrl != window.location.href) {
console.log("【自动识别填充验证码】页面/验证码已更新,正在识别...");
tempUrl = window.location.href;
start();
}
});
}, 500)
})();