🏠 Home 

通途

为途教务系统验证码识别

  1. // ==UserScript==
  2. // @name 通途
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.5.8
  5. // @description 为途教务系统验证码识别
  6. // @author kaka
  7. // @match http://jwc.swjtu.edu.cn/service/login*
  8. // @match *://jiaowu.swjtu.edu.cn/service/login*
  9. // @match http://jwc.swjtu.edu.cn/vatuu/YouthIndexAction?setAction=index
  10. // @match http://jwc.polus.edu.cn/service/login*
  11. // @match http://jwc.abtu.edu.cn/service/login*
  12. // @match http://jwb.sqmc.edu.cn/service/login*
  13. // @match http://jwc.svtcc.edu.cn/service/login*
  14. // @match http://jwc.scuvc.com/service/login*
  15. // @match http://jwxt.stbu.edu.cn/service/login*
  16. // @match *.vatuu.com/service/login*
  17. // @match *.vvtuu.com/service/login*
  18. // @connect aip.baidubce.com
  19. // @connect localhost
  20. // @grant unsafeWindow
  21. // @grant GM_xmlhttpRequest
  22. // @grant GM_getValue
  23. // @grant GM_setValue
  24. // @run-at document-end
  25. // ==/UserScript==
  26. (function() {
  27. 'use strict';
  28. let setting = {//改一改这个,应该能用于其他网站,慢慢适配
  29. ////////////////////////////////////////////////////////////////////////////////////////////user-setting
  30. ran_img:function(){return document.querySelector("#randomPhoto > img")}, /*验证码图片元素*/
  31. ran_img_url:window.location.origin+'/vatuu/GetRandomNumberToJPEG?test='+new Date().getTime(),/*验证码图片请求url*/
  32. ran_text:function(){return document.getElementById('ranstring')},/*验证码填写元素*/
  33. other_data:['document.querySelector("#password")',/*其它必填项#######################自动处理,下次跟新再说(逃*/
  34. 'document.querySelector("#username")'],/*必须是字符串,目前想不到更好的解决办法*/
  35. submit:document.querySelector("#submit2"),/*登陆按钮*/
  36. add_onload_listener:1,//是否需要在切换验证码后对图片元素监听
  37. autologin:false,//自动登录开关
  38. //////////////////////////////////////////////////////////////////////////////////////////////other-setting
  39. nostop:true,/*错误后允许重试*/
  40. err_total:10, /*各环节允许最大错误*/
  41. debugger:0,//调试开关
  42. done:0,
  43. ocrurl: "https://aip.baidubce.com/rest/2.0/ocr/v1/webimage",//api地址
  44. ocrurl_1: "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic",//备用api
  45. apis:[['iKGARn6BhGgU82W9xzLUIatb','hES0Zae2iLdP1iotenC8zlGo9qA3r0Hc'],
  46. ],
  47. };
  48. ////////////////////////////////////////////////////////////////其它网址匹配
  49. if(/bslc.lib.swjtu.edu.cn/.test(window.location.href)){
  50. debug('lib')
  51. setting.ran_img= function(){return document.querySelector("#kaptcha")}
  52. setting.ran_text= function(){return document.querySelector("#code")}
  53. setting.ran_url= "https://bslc.lib.swjtu.edu.cn/uas/kaptcha.jpg"
  54. setting.other_data= ['document.querySelector("#userid")','document.querySelector("#password")']
  55. setting.submit= document.querySelector("#form1 > div:nth-child(10) > button")
  56. //setting.autologin=true,//自动登录开关
  57. }
  58. /////////////////////////////////////////////////////////////
  59. function autologin(){
  60. if(other_data_done()){/*其它信息也填了就登陆*/
  61. setting.submit.click();
  62. };
  63. };
  64. function add_onload(){
  65. if(setting.add_onload_listener){
  66. try{
  67. let img =setting.ran_img()//再次添加监听
  68. img.addEventListener("load",function(){
  69. get_random_img(function( bs64_str){
  70. get_str(bs64_str)
  71. })
  72. })
  73. }catch(e){}
  74. }
  75. }
  76. function debug(){
  77. if(setting.debugger){
  78. const arg = Array.from(arguments);
  79. arg.unshift(`color: white; background-color:#2274A5`);
  80. arg.unshift('%c 通途:');
  81. console["info"].apply(console, arg);
  82. }
  83. }
  84. function enter_login(){
  85. document.onkeydown = function(ev){
  86. var e = ev || event;
  87. if(e.keyCode ==13){
  88. setting.submit.click();
  89. };
  90. }};
  91. function other_data_done(){
  92. if(eval(setting.other_data.join('.value&&')+'.value')){return true;};
  93. };
  94. function get_random_img(callback){
  95. setting.runing=1
  96. let img= setting.ran_img()
  97. debug(img)
  98. let canvas = document.createElement("canvas");
  99. canvas.width = img.width;
  100. canvas.height = img.height;
  101. let ctx = canvas.getContext("2d");
  102. ctx.drawImage(img, 0, 0, img.width, img.height);
  103. let ext = img.src.substring(img.src.lastIndexOf(".")+1).toLowerCase();
  104. let dataURL = canvas.toDataURL("image/"+ext);
  105. let bs64_str = dataURL.split(",")[1];
  106. callback(bs64_str);
  107. };
  108. function get_access_url(){
  109. let randomapi = setting.apis[setting.ran_api_num];
  110. return 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id='+randomapi[0]+'&client_secret='+randomapi[1]
  111. };
  112. function setCookie(cname, cvalue, exp) {
  113. var d = new Date();
  114. d.setTime(d.getTime() + (exp*1000)-5000);
  115. var expires = "expires="+d.toUTCString();
  116. document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
  117. };
  118. function getCookie(cname) {
  119. var name = cname + "=";
  120. var ca = document.cookie.split(';');
  121. for(var i = 0; i < ca.length; i++) {
  122. var c = ca[i];
  123. while (c.charAt(0) == ' ') {
  124. c = c.substring(1);
  125. };
  126. if (c.indexOf(name) == 0) {
  127. return c.substring(name.length, c.length);
  128. };
  129. };
  130. return "";
  131. };
  132. function get_access(){
  133. debug("api-num",setting.ran_api_num)
  134. debug("api-url",setting.ocrurl)
  135. let access_token = getCookie("access_token_"+setting.ran_api_num);
  136. if (access_token != "") {/*access未过期*/
  137. setting.access_token =access_token;
  138. } else {
  139. try{
  140. GM_xmlhttpRequest({
  141. method: "GET",
  142. url:get_access_url(),
  143. onload: function(response) {
  144. let access_token =JSON.parse(this.responseText)["access_token"];
  145. let expires =JSON.parse(this.responseText)["expires_in"];
  146. setCookie("access_token_"+setting.ran_api_num, access_token, expires);
  147. setting.access_token = access_token;
  148. }
  149. });
  150. }catch(err){
  151. debug("response1",response.responseText)
  152. if( err_access_num<=setting.err_total){
  153. err_access_num+=1;
  154. get_access();
  155. }else{
  156. setting.ran_text().placeholder = '失败,请自行输入';
  157. }
  158. }
  159. }
  160. }
  161. function get_str(bs64_str){
  162. if(setting.done){debug('已填写,取消操作')
  163. return}
  164. let request_url = setting.ocrurl + "?access_token=" + setting.access_token;
  165. let data = 'image='+encodeURIComponent(bs64_str);
  166. /*alert(encodeURIComponent(bs64_str));*/
  167. GM_xmlhttpRequest({
  168. method: 'POST',
  169. url: request_url,
  170. data: data,
  171. headers: {
  172. 'charset': 'UTF-8',
  173. "Content-Type": "text/plain"
  174. },
  175. onload: function(response) {
  176. /* console.log("baidu_response");*/
  177. debug(response.responseText)
  178. let temp = JSON.parse(response.responseText);
  179. if(temp['error_code']==17){
  180. debug('服务器请求超限',setting.ran_api_num)
  181. let lastapi=setting.apis[setting.ran_api_num]
  182. setting.apis[setting.ran_api_num]=0//标记超限的
  183. debug(setting.apis)
  184. for(let i=0;i<setting.apis.length;i++){
  185. if(setting.apis[i]!=0){
  186. setting.ran_api_num = i
  187. get_random_img(function( bs64_str){
  188. get_access();
  189. get_str(bs64_str);
  190. throw "超限"
  191. }
  192. )
  193. }
  194. }
  195. setting.ocrurl= setting.ocrurl_1//使用备用识别url
  196. setting.apis[setting.ran_api_num]=lastapi
  197. get_random_img(function( bs64_str){
  198. get_access();
  199. get_str(bs64_str);
  200. }
  201. )
  202. setting.ran_text().placeholder = '今日请求超限';
  203. debug('无可用')
  204. return
  205. }else if(temp['error_code']&& temp['error_code']!= 18&& temp['error_code']!= 110){
  206. setting.ran_text().placeholder = '服务器访问出错';
  207. return
  208. }
  209. try{
  210. let rand_str = temp['words_r###lt'][0]['words'].trim();
  211. debug("解析结果",rand_str)
  212. if(rand_str.length == 4){
  213. setting.ran_text().value = rand_str; /*填写验证码 */
  214. if(other_data_done()&&setting.autologin){/*其它信息也填了就登陆*/
  215. setting.submit.click();
  216. };
  217. debug('已填写')
  218. setting.done=1
  219. //add_onload()//添加监听
  220. }else{ /*重来*/
  221. throw "解析失败";
  222. };
  223. }catch(err){
  224. setTimeout(function(){
  225. if(setting.nostop){
  226. if(setting.err_num<=setting.err_total ){
  227. setting.err_num+=1;
  228. debug('重试次数:'+setting.err_num)
  229. setting.ran_text().placeholder = '失败,重试中...';
  230. //if(setting.done){debug('已填写,取消操作') return}
  231. setting.ran_img().click()//切换验证码
  232. add_onload()
  233. }else{
  234. setting.ran_text().placeholder = '失败,请自行输入';
  235. return;
  236. }
  237. };
  238. },200)
  239. };
  240. }
  241. });
  242. };
  243. function init(){
  244. setting.runing=0;
  245. setting.err_num = 1;
  246. let err_access_num = 1;
  247. setting.ran_api_num = Math.floor(Math.random() * setting.apis.length);
  248. enter_login();
  249. debug(setting.ran_text())
  250. //setting.ran_text().addEventListener('focus',function(){setting.nostop=false; setting.ran_text().placeholder = '检测到自行输入';})/*用户选择自己写时,阻止继续执行*/
  251. }
  252. function main(){
  253. let img =setting.ran_img()
  254. debug(img)
  255. img.addEventListener("load",function(){
  256. setting.ran_text().placeholder = '尝试获取验证码中';
  257. get_random_img(function( bs64_str){
  258. get_access();
  259. get_str(bs64_str);
  260. });
  261. /*setInterval(autologin,3000)//适合自己用*/
  262. autologin();/*针对浏览器预先填写的用户*/
  263. // setInterval(add_onload,10);目的是验证码错误后再次尝试,但好像有点问题,如何区分谁改的img标签,脚本还是源网页
  264. })
  265. }
  266. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  267. init();
  268. main();
  269. var yalert = window.alert
  270. function newalert(msg){
  271. if('验证码输入不正确' == msg&&setting.nostop){
  272. debug('检测到alert,验证码输入不正确,开始执行main',msg)
  273. setting.ran_text().value = ''
  274. setting.done = false
  275. setting.autologin = true
  276. setting.ran_img().click()//切换验证码
  277. add_onload()
  278. setting.err_num+=1;
  279. }else{
  280. yalert(msg)
  281. }
  282. }
  283. unsafeWindow.alert = newalert
  284. let isrun= setInterval(function(){//发现会概率性不执行,推测是因为上面onload的锅,先加个检测
  285. console.log(setting.runing)
  286. if(setting.runing){
  287. clearInterval(isrun)
  288. }else{
  289. debug('run main')
  290. setting.ran_text().placeholder = '尝试获取验证码中';
  291. get_random_img(function( bs64_str){
  292. get_access();
  293. get_str(bs64_str);
  294. }
  295. )
  296. }
  297. },100)
  298. })();