浙大教务网登录验证码自动填充--chrome插件开发
一、前言
女朋友说“教务网每次登录都要输入验证码,好麻烦啊”,“啊,那我把它破解了吧…”。想起之前看到了“求是潮”开发的选课插件,可以在选课时看到“学习帝”对老师的评价之类的,所以想要不也开发个chrome插件试试吧。
二、验证码图像识别
教务网的验证码还是比较良心的,就是5个数字加点背景干扰,如下图:
为了做个验证码图像识别,主要包括以下几步:
1、爬取1000张验证码图片,验证码地址是 http://jwbinfosys.zju.edu.cn/CheckCode.aspx ;这和网上的静态图片(地址以img、png等结尾的图片)有点不一样,但是用python还是可以很方便地爬取(其实我也是试了一下不小心发现可以爬下来…有点激动):
import urllib.request
url='http://jwbinfosys.zju.edu.cn/CheckCode.aspx'
for i in range(1000):
urllib.request.urlretrieve(url,'imgs/'+str(i)+'.png') #请保证当前目录下有imgs文件夹,没有的话新建一个
之后就可以看到imgs目录下的图片了:
2、将图像二值化,再将图片切割成5张包含单个数字的图片。切割的时候读取图片,将其转换为数组,手动调试,选取合适的切割位置。验证码的size是60x22,最终我选择的切割下标是[3,13],[13,23],[22,32],[31,41],[41,51],即每张小图片的size是10x22。
Code:
from PIL import Image
import cv2 as cv
import numpy as np
import os
#如果不存在相应的文件夹,请先创建改文件夹
def binary():
file_list=os.listdir('imgs/')
for file in file_list:
img=np.array(Image.open('imgs/'+file).convert('L'),'f')
ret,dst=cv.threshold(img,150,255,cv.THRESH_BINARY)
cv.imwrite('binary/'+file.split('.')[0]+'.jpg',dst)
def single():
indexs=[[3,13],[13,23],[22,32],[31,41],[41,51]]
file_list=os.listdir('binary/')
k=0
for file in file_list:
img=np.array(Image.open('binary/'+file))
for index in indexs:
cv.imwrite('single/'+str(k)+'.jpg',img[:,index[0]:index[1]])
k+=1
最终得到如下图片集:
3、得到包含单个数字的图片集之后,对图片进行分类。由于这里的数字太规则了,用不上神经网络,直接用KNN(其实是类似于KNN的方法;一开始混淆了KNN和K-means,感谢青神的指导)进行分类。
首先人工选取几个“中心”,每个数字选取8个“中心”吧;然后针对每张图片,计算它到每个数字的8个“中心”的距离(将图片像素矩阵转换为1维数组,计算欧式距离)的平均值,最小的那个平均值所对应的数字就是这张图片所属的类别。
由于图片规范,经过人工比对,第一轮筛选就有较高的准确率。
因此,从第一轮筛选出的结果中选取更多的样本用来扩充每个数字对应的“中心”的个数。
继续进行筛选-扩充,直到准确率满足要求。
意外发现,验证码里面没有9这个数字,是不是感觉白用了4年的教务网,意不意外。
Code:
#当前目录下要有center文件夹,center文件夹中包含“0~8”共9个文件夹,每个文件夹下包含8个预选的“中心”
#当前目录下要有一个result文件夹,result文件夹中包含“0~8”共9个空文件夹,用来保存KNN分类的结果
def knn(img_file):
img=np.array(Image.open(img_file))
ret,dst=cv.threshold(img,100,10,cv.THRESH_BINARY_INV)
dst.resize((1,img.shape[0]*img.shape[1]))
distance=[]
for i in range(9):
dis=[]
file_list=os.listdir('center/'+str(i)+'/')
for file in file_list:
sam=np.array(Image.open('center/'+str(i)+'/'+file))
ret,sam_dst=cv.threshold(sam,100,10,cv.THRESH_BINARY_INV)
sam_dst.resize((1,sam.shape[0]*sam.shape[1]))
dis.append(np.sqrt(np.sum(np.square(dst-sam_dst))))
distance.append(np.mean(dis))
k_class=np.argmin(distance)
cv.imwrite('result/'+str(k_class)+'/'+img_file[7:],img)
for k in range(5000):
knn('single/'+str(k)+'.jpg')
最后得到如下数据集:
利用该数据集和KNN,就可以对单独一张验证码图片进行数字识别。
三、chrome插件开发
Google还是很友好的,允许大家自由、免费开发插件,这里只针对Chrome开发插件,其余的浏览器暂时不考虑。推荐大家使用Chrome浏览器,记得几个月前使用Edge的时候,几个G的视频,下到一半就中断了,也不支持断点续传,而且还有各种意想不到的问题,比如vpn登录网页打不开,反正一句话,用Chrome没错。
又想起几年前用360安全浏览器被人无情地嘲笑,其实360浏览器也还行,真的不差,用了2年没发现有啥问题
开发过程中还是遇到了许多难题的,毕竟第一次,这些就不赘述了,直接说最后的可行的方法吧。
方法是这样的:Chrome插件读取教务网本地cookie,将cookie发送给我的云服务器api,云服务器利用api收到的cookie在后台对 http://jwbinfosys.zju.edu.cn/CheckCode.aspx 进行一次Get请求并将该次请求得到的图片保存,云服务器对该图片进行验证码识别并将结果通过api return给Chrome插件,Chrome插件将结果填充到验证码输入框并点击“登录”按钮。
这里需要注意一下,云服务器在后台是对验证码地址进行一次Get请求,而不是对教务网地址进行一次请求;这也是我这一次突然想到的一个问题,以前可能一直没注意到这一点。
由于插件开发和服务器的代码不太好展示,这里就不贴出来了。
四、插件使用和结果展示
下载地址:还在完善中,暂不提供。。。过几天,等新生军训完了发个十大。。。
使用方法:把压缩包解压,在chrome扩展程序里面“加载已解压的扩展程序”;打开教务网主页,一般都自动填好了用户名和密码,单击一下插件图标,就可以登录了。
使用效果:(涉及个人隐私,把gif删了)
可惜了,被退学了。。。早几年开发出来就好了,白敲了4年的验证码了。。。
五、未来展望
1、在一学期一次的“教师评价”中,增加“一键评价”功能 ;
2、提升一下验证码的识别准确率和速度;
3、还在想;
4、突然想到,某些网站,比如申请借用教室的网站,每次都要填很多重复的信息,要不来个一键填写吧。。。
5、又突然想到,机械学院官网的文件,每次下载下来文件名都是一堆垃圾字符,诶,那我改一下好了!(可惜我也不用下载了,过段时间找辅导员推广一下吧)
改之前:
改之后:
真是,谁用谁说好!
六、提示
1、解压插件压缩包的时候可以看到源码,收集的网站cookie只包含一个无实际意义的参数,不涉及用户的账号、密码,请放心使用;
2、由于验证码识别率还不是100%,可能会出现验证码错误的情况,那就再重新试一次好了;
3、使用前请保证浏览器已经记住了用户名和密码并且已经自动填好了;
4、你会看到自动填充的验证码和图片不一致,这是正常的;
5、暂时无法到应用商店发布,因为注册成为发布者要钱。