为途教务系统验证码识别
// ==UserScript== // @name 通途 // @namespace http://tampermonkey.net/ // @version 2.5.8 // @description 为途教务系统验证码识别 // @author kaka // @match http://jwc.swjtu.edu.cn/service/login* // @match *://jiaowu.swjtu.edu.cn/service/login* // @match http://jwc.swjtu.edu.cn/vatuu/YouthIndexAction?setAction=index // @match http://jwc.polus.edu.cn/service/login* // @match http://jwc.abtu.edu.cn/service/login* // @match http://jwb.sqmc.edu.cn/service/login* // @match http://jwc.svtcc.edu.cn/service/login* // @match http://jwc.scuvc.com/service/login* // @match http://jwxt.stbu.edu.cn/service/login* // @match *.vatuu.com/service/login* // @match *.vvtuu.com/service/login* // @connect aip.baidubce.com // @connect localhost // @grant unsafeWindow // @grant GM_xmlhttpRequest // @grant GM_getValue // @grant GM_setValue // @run-at document-end // ==/UserScript== (function() { 'use strict'; let setting = {//改一改这个,应该能用于其他网站,慢慢适配 ////////////////////////////////////////////////////////////////////////////////////////////user-setting ran_img:function(){return document.querySelector("#randomPhoto > img")}, /*验证码图片元素*/ ran_img_url:window.location.origin+'/vatuu/GetRandomNumberToJPEG?test='+new Date().getTime(),/*验证码图片请求url*/ ran_text:function(){return document.getElementById('ranstring')},/*验证码填写元素*/ other_data:['document.querySelector("#password")',/*其它必填项#######################自动处理,下次跟新再说(逃*/ 'document.querySelector("#username")'],/*必须是字符串,目前想不到更好的解决办法*/ submit:document.querySelector("#submit2"),/*登陆按钮*/ add_onload_listener:1,//是否需要在切换验证码后对图片元素监听 autologin:false,//自动登录开关 //////////////////////////////////////////////////////////////////////////////////////////////other-setting nostop:true,/*错误后允许重试*/ err_total:10, /*各环节允许最大错误*/ debugger:0,//调试开关 done:0, ocrurl: "https://aip.baidubce.com/rest/2.0/ocr/v1/webimage",//api地址 ocrurl_1: "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic",//备用api apis:[['iKGARn6BhGgU82W9xzLUIatb','hES0Zae2iLdP1iotenC8zlGo9qA3r0Hc'], ], }; ////////////////////////////////////////////////////////////////其它网址匹配 if(/bslc.lib.swjtu.edu.cn/.test(window.location.href)){ debug('lib') setting.ran_img= function(){return document.querySelector("#kaptcha")} setting.ran_text= function(){return document.querySelector("#code")} setting.ran_url= "https://bslc.lib.swjtu.edu.cn/uas/kaptcha.jpg" setting.other_data= ['document.querySelector("#userid")','document.querySelector("#password")'] setting.submit= document.querySelector("#form1 > div:nth-child(10) > button") //setting.autologin=true,//自动登录开关 } ///////////////////////////////////////////////////////////// function autologin(){ if(other_data_done()){/*其它信息也填了就登陆*/ setting.submit.click(); }; }; function add_onload(){ if(setting.add_onload_listener){ try{ let img =setting.ran_img()//再次添加监听 img.addEventListener("load",function(){ get_random_img(function( bs64_str){ get_str(bs64_str) }) }) }catch(e){} } } function debug(){ if(setting.debugger){ const arg = Array.from(arguments); arg.unshift(`color: white; background-color:#2274A5`); arg.unshift('%c 通途:'); console["info"].apply(console, arg); } } function enter_login(){ document.onkeydown = function(ev){ var e = ev || event; if(e.keyCode ==13){ setting.submit.click(); }; }}; function other_data_done(){ if(eval(setting.other_data.join('.value&&')+'.value')){return true;}; }; function get_random_img(callback){ setting.runing=1 let img= setting.ran_img() debug(img) let canvas = document.createElement("canvas"); canvas.width = img.width; canvas.height = img.height; let ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0, img.width, img.height); let ext = img.src.substring(img.src.lastIndexOf(".")+1).toLowerCase(); let dataURL = canvas.toDataURL("image/"+ext); let bs64_str = dataURL.split(",")[1]; callback(bs64_str); }; function get_access_url(){ let randomapi = setting.apis[setting.ran_api_num]; return 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id='+randomapi[0]+'&client_secret='+randomapi[1] }; function setCookie(cname, cvalue, exp) { var d = new Date(); d.setTime(d.getTime() + (exp*1000)-5000); var expires = "expires="+d.toUTCString(); document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/"; }; function getCookie(cname) { var name = cname + "="; var ca = document.cookie.split(';'); for(var i = 0; i < ca.length; i++) { var c = ca[i]; while (c.charAt(0) == ' ') { c = c.substring(1); }; if (c.indexOf(name) == 0) { return c.substring(name.length, c.length); }; }; return ""; }; function get_access(){ debug("api-num",setting.ran_api_num) debug("api-url",setting.ocrurl) let access_token = getCookie("access_token_"+setting.ran_api_num); if (access_token != "") {/*access未过期*/ setting.access_token =access_token; } else { try{ GM_xmlhttpRequest({ method: "GET", url:get_access_url(), onload: function(response) { let access_token =JSON.parse(this.responseText)["access_token"]; let expires =JSON.parse(this.responseText)["expires_in"]; setCookie("access_token_"+setting.ran_api_num, access_token, expires); setting.access_token = access_token; } }); }catch(err){ debug("response1",response.responseText) if( err_access_num<=setting.err_total){ err_access_num+=1; get_access(); }else{ setting.ran_text().placeholder = '失败,请自行输入'; } } } } function get_str(bs64_str){ if(setting.done){debug('已填写,取消操作') return} let request_url = setting.ocrurl + "?access_token=" + setting.access_token; let data = 'image='+encodeURIComponent(bs64_str); /*alert(encodeURIComponent(bs64_str));*/ GM_xmlhttpRequest({ method: 'POST', url: request_url, data: data, headers: { 'charset': 'UTF-8', "Content-Type": "text/plain" }, onload: function(response) { /* console.log("baidu_response");*/ debug(response.responseText) let temp = JSON.parse(response.responseText); if(temp['error_code']==17){ debug('服务器请求超限',setting.ran_api_num) let lastapi=setting.apis[setting.ran_api_num] setting.apis[setting.ran_api_num]=0//标记超限的 debug(setting.apis) for(let i=0;i<setting.apis.length;i++){ if(setting.apis[i]!=0){ setting.ran_api_num = i get_random_img(function( bs64_str){ get_access(); get_str(bs64_str); throw "超限" } ) } } setting.ocrurl= setting.ocrurl_1//使用备用识别url setting.apis[setting.ran_api_num]=lastapi get_random_img(function( bs64_str){ get_access(); get_str(bs64_str); } ) setting.ran_text().placeholder = '今日请求超限'; debug('无可用') return }else if(temp['error_code']&& temp['error_code']!= 18&& temp['error_code']!= 110){ setting.ran_text().placeholder = '服务器访问出错'; return } try{ let rand_str = temp['words_r###lt'][0]['words'].trim(); debug("解析结果",rand_str) if(rand_str.length == 4){ setting.ran_text().value = rand_str; /*填写验证码 */ if(other_data_done()&&setting.autologin){/*其它信息也填了就登陆*/ setting.submit.click(); }; debug('已填写') setting.done=1 //add_onload()//添加监听 }else{ /*重来*/ throw "解析失败"; }; }catch(err){ setTimeout(function(){ if(setting.nostop){ if(setting.err_num<=setting.err_total ){ setting.err_num+=1; debug('重试次数:'+setting.err_num) setting.ran_text().placeholder = '失败,重试中...'; //if(setting.done){debug('已填写,取消操作') return} setting.ran_img().click()//切换验证码 add_onload() }else{ setting.ran_text().placeholder = '失败,请自行输入'; return; } }; },200) }; } }); }; function init(){ setting.runing=0; setting.err_num = 1; let err_access_num = 1; setting.ran_api_num = Math.floor(Math.random() * setting.apis.length); enter_login(); debug(setting.ran_text()) //setting.ran_text().addEventListener('focus',function(){setting.nostop=false; setting.ran_text().placeholder = '检测到自行输入';})/*用户选择自己写时,阻止继续执行*/ } function main(){ let img =setting.ran_img() debug(img) img.addEventListener("load",function(){ setting.ran_text().placeholder = '尝试获取验证码中'; get_random_img(function( bs64_str){ get_access(); get_str(bs64_str); }); /*setInterval(autologin,3000)//适合自己用*/ autologin();/*针对浏览器预先填写的用户*/ // setInterval(add_onload,10);目的是验证码错误后再次尝试,但好像有点问题,如何区分谁改的img标签,脚本还是源网页 }) } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// init(); main(); var yalert = window.alert function newalert(msg){ if('验证码输入不正确' == msg&&setting.nostop){ debug('检测到alert,验证码输入不正确,开始执行main',msg) setting.ran_text().value = '' setting.done = false setting.autologin = true setting.ran_img().click()//切换验证码 add_onload() setting.err_num+=1; }else{ yalert(msg) } } unsafeWindow.alert = newalert let isrun= setInterval(function(){//发现会概率性不执行,推测是因为上面onload的锅,先加个检测 console.log(setting.runing) if(setting.runing){ clearInterval(isrun) }else{ debug('run main') setting.ran_text().placeholder = '尝试获取验证码中'; get_random_img(function( bs64_str){ get_access(); get_str(bs64_str); } ) } },100) })();