通途

为途教务系统验证码识别

// ==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)

    })();