正⽅验证码智能识别及教务系统模拟登录
⽂章⽬录
前⾔
之前写了⼀个正⽅教务系统登录的程序,当时验证码使⽤的是⼿动输⼊,觉得太了,这种⽤途的脚本怎么可以让这种⼩⼩验证码拦住呢!︿( ̄︶ ̄)︿,我们要的可是完全不要⼈⼯的爬⾍啊!你可知道!┑( ̄Д  ̄)┍
有想法很好,我们就开始做吧!
⼀、验证码数据集获取
这⾥我从github上下载了数据集,⼤概五百张图⽚,⾮常感谢其提供者。
数据集我放在我的源码⾥⾯了,需要的话,可以⾃⾏下载,github链接在底部,此处不赘述。
⼆、图像处理
2.1 验证码图⽚转灰度、⼆值化、去噪点
def GrayscaleAndBinarization(image):
'''
灰度并⼆值化图⽚
:param image:
:return:
'''
threshold =17# 需要⾃⼰调节阈值,17效果不错哦!
tmp_image = vert('L')# 灰度化
new_image = w('L', tmp_image.size,0)
# 初步⼆值化
for i in range(tmp_image.size[1]):
for j in range(tmp_image.size[0]):
if pixel((j, i))> threshold:
new_image.putpixel((j, i),255)
else:
new_image.putpixel((j, i),0)
# 去噪,去除独⽴点,将前后左右等九宫格中灰度通道值均为255的像素点的通道值设为255
for i in range(1, new_image.size[1]-1):
for j in range(1, new_image.size[0]-1):
if pixel((j, i))==0and pixel((j -1, i))==255and pixel((j +1, i))==255and \
pixel((j, i -1))==255and pixel((j -1, i -1))==255and pixel((j +1, i -1))==255and \
pixel((j, i +1))==255and pixel((j -1, i +1))==255and pixel((j +1, i +1))==255:
new_image.putpixel((j, i),255)
return new_image
2.2 对图像进⾏切割
在训练之前,我们需要获取每个字符的数据,作为训练集,所以我们把验证码中的字符切割开来。之前我还使⽤算法进⾏检测切割位置,后来发现完全没有必要啊!(=。=),验证码中总共四个字符,我⽤⼿指⼀⽐,其中每个字母都处于⼤致区间内,这就简单了我们的⼯作,我们只要在固定的区间内进⾏切割,就能保证四个字符能够完好的被分开。
def SplitImage(image):
'''
切割图像并保存,关键在于寻切割位置
:param image:
:return:
'''
splitSite =[0,16,28,41]# 这个位置⾮常好,nice
splitSite.append(54)
# 对图⽚进⾏切割
new_image =[]
for index in range(1,len(splitSite)):
box =(splitSite[index -1],0, splitSite[index], image.size[1])
new_image.p(box))
return new_image
2.3 批量处理图⽚数据
下⾯的是数据集⽂件夹。
⾸先我们写⼀个函数获取该⽂件夹下验证码⽂件的⽂件名,作为标签。
def GetFileName(filePath):
'''
返回指定⽂件夹下⽂件的⽂件名
:param filePath:
:return:
'''
filenames =[]
for filename in os.listdir(filePath):
filenames.append(filename)
return filenames
接下来我们批处理所有图⽚
def SplitAllImage():
'''
分割所有图⽚
:return:
'''
# dict 记录每个字符的数⽬
dict={
'0':0,'1':0,'2':0,'3':0,'4':0,'5':0,'6':0,'7':0,'8':0,'9':0,
'a':0,'b':0,'c':0,'d':0,'e':0,'f':0,'g':0,'h':0,'i':0,'j':0,'k':0,'l':0,'m':0,'n':0,
'o':0,'p':0,'q':0,'r':0,'s':0,'t':0,'u':0,'v':0,'w':0,'x':0,'y':0,'z':0
}
filenames = GetFileName('./images/data_biaoji')
for item in filenames:# 图⽚名称
image = Image.open('./images/data_biaoji/{}'.format(item))
tmp_image = GrayscaleAndBinarization(image)
data_image = SplitImage(tmp_image)
for i in range(len(data_image)):# 此处值为4,对切割后的四张图⽚进⾏处理
dict[item[i]]=dict[item[i]]+1
data_image[i]= data_image[i].resize((14,27))
data_image[i].save('./images/data/{}/{}.jpg'.format((item[i]),dict[item[i]]))# 总共获取了1884张图⽚
print(dict)
三、图像特征提取
机器如何能够识别图像的呢?当然是转化为机器识别的数字啊!这时我们将经图像处理后的图⽚进⾏特征提取,将各个像素的通道值提取到⼀个列表中。
3.1 所有图像特征值提取
def returnDataAndLabel(path='./images/data'):
'''
返回全部数据
:param path: 图⽚路径
:return: data 和 label
'''
raw =[]
datas =[]# 特征
labels =[]# 标记
for item1 in os.listdir(path):# ⽂件路径
label = item1
for item2 in os.listdir(path +'/'+ item1):
data =[]
image = Image.open(path +'/'+ item1 +'/'+ item2).resize((14,27)) for i in range(image.size[1]):# 读取像素通道值
for j in range(image.size[0]):
data.pixel((j, i)))
data.append(label)# ⼀张图⽚的数据
if len(data)==(14*27+1):# 图⽚尺⼨
raw.append(data)
for i in range(len(raw)):
tmp_data = raw[i][:-1]
tmp_label = raw[i][-1]
labels.append(tmp_label)
datas.append(tmp_data)
return datas, labels
3.2 单张图⽚特征值提取
def featuretransfer(image):
'''
返回特征向量,预测时⽤
:param image: 图像
:param label: 图像所属标签
:
return: 特征向量
'''
features =[]
image = size((14,27))
for i in range(image.size[1]):
for j in range(image.size[0]):
features.pixel((j, i)))
return features
四、模型训练
集成学习较⼀般学习器往往有较好的效果,此处使⽤了随机森林算法
def trainModel(datas, labels, isSave=True, path='./del'):
'''
训练模型
:param datas: 数据集
:param labels: 标签
:return: 模型
'''
X_train, X_test, y_train, y_test = train_test_split(datas, labels, test_size=0.3, random_state=30)
clf = RandomForestClassifier(n_estimators=500, max_depth=10, min_samples_split=10, random_state=0)
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
score = accuracy_score(y_test, y_pred)
print('Accuracy score:', score)
if isSave:
joblib.dump(clf, path)
return clf
ps: 最后发现效果不错,单个字符识别正确率能达到84%多,模型没有调参,有兴趣的同学可以继续调节使准确率更⾼。但这⾥我⼜想到了⼀点,单个字符识别率有84%,但正⽅验证码有四个字符,准确率那就是84%*84%*84%*84% = 0.49,妈呀!识别率⼀下降了这么多,能⽤吗??
五、实际测试
测试主要使⽤正⽅教务系统进⾏登录进⾏实际测试,这⾥有关爬⾍,就不细说了,登录代码摆上
import requests
from pyquery import PyQuery as pq
from urllib import parse
als import joblib
from ProcessingImage import*# ⾃定义模块
import re
import json
class SCHOOL(object):
def__init__(self):
self.headers ={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:60.0) Gecko/20100101 Firefox/60.0',
}
self.username ='**********'# 学号
self.password ='**********'# 密码
self.name =''
self.url_base ='***.***.***.***/'# 这⾥换成⾃⼰学校的地址
self.raw_url = self.url_base +'default2.aspx'
self.url_1 =''
self.login_url =''getsavefilename
self.session = requests.Session()
<_real_url()
self.login()
def get_real_url(self):
'''
获取真实的登录url
:return:
'''
response1 = (self.raw_url, headers=self.headers)
self.login_url = response1.url
self.url_1 = al_url +'/xs_main.aspx?xh='+ self.username
def loadModel(self, filename):

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。