// ==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_result'][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)
})();