通途

为途教务系统验证码识别

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

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

    })();