学生利用python破解验证码,模拟登录教务处查看成绩、抢课!

学生利用python破解验证码,模拟登录教务处查看成绩、抢课!

Python 的概念

正式进入主题,每学期末都要抢课,学校的服务器还贼渣。

先说一个简单的的方法,抓包,不断地发起选课请求,但有一个明显的缺点,那就是cookies容易过期。

还得重新登陆替换cookies。于是,就有了今天要分享的内容。

其大概分为两个部分:1.自动登录教务处;

2.查看成绩、抢课.

考虑到有些童鞋没有图像处理的经验,我会把训练好的结果直接给大家。今天先写第一个自动登录。

自动登录教务处

自动登陆教务处时,解决两个主要问题: 1.验证码的识别;2.cookies的获取

验证码识别

1. 想要识别验证码,最起码知道验证码的url才能下载下来。其url地址:http://{}/CheckCode.aspx {}

代表着相应的域名或ip地址。

2. 将验证码下载下来,其代码十分简单,后面会给放上代码的。得到验证码。如下图

学生利用python破解验证码,模拟登录教务处查看成绩、抢课!

3.接下来的过程很重要,对验证码进行数字图像处理,把图片里的字母一个个的分割出来。怎么做呢?

3.1先观察图像中的字符都蓝色的,可以提取RGB三色通道中的B通道。得到图像

学生利用python破解验证码,模拟登录教务处查看成绩、抢课!

3.2注意到图片中的小点点了没有,在数字图像中,这种情况称之为椒盐噪声,对这种噪声的处理呢,一般用的方法是中值滤波当然,也可 以根据B通道图像的特点,自己写一个更合适的算法。这里时间比较紧,就直接采用中值滤波,并图像增强,得到图像

学生利用python破解验证码,模拟登录教务处查看成绩、抢课!

3.3 嗯,在这里补充一点,我觉得自己写的算法应该比这种普遍的处理方法要好的多,强烈建议有能力的童鞋自己写一写,估计github、博客上已经有相关代码了。得到上图像,将图像进行二值化,先观察期灰度分布直方图,确定阈值为160(当然阈值可以适当的调整),最后,进行二值化。

学生利用python破解验证码,模拟登录教务处查看成绩、抢课!

灰度直方图

学生利用python破解验证码,模拟登录教务处查看成绩、抢课!

二值化之后的图像

3.4 将图片分割成单个的字符,采用的分割距离为[5,16,29,38,53]

学生利用python破解验证码,模拟登录教务处查看成绩、抢课!

效果图

学生利用python破解验证码,模拟登录教务处查看成绩、抢课!

全部分割完成

3.5 将得到的字符串与正确的验证码用机器学习中的KNN算法进行训练,当然也可以用RNN等算法,它的精确度什么的统统没计算,感觉准确度在80%左右。我的小破笔记本跑不了很多数据,见谅呀!

当然,你也可以采用不同的算法进行训练,其性能什么的可以做一下比对。得到结果集,保存出来,为下一次预测准备。放心吧,得到的结果以附件的形式发出来的。直接拿来用就好了。

以上内容呢,虽然没有代码,但是思路已经写得很清楚了,我写的代码有点乱,有点不好意思发出来。想要的话可以在帖子下面留言,如果想看的人多的话,我会整理整理发出来的。哦,差点忘了,所用的库有 numpy、PIL(2.7.x,三对应版本应该是pillow-pil记不太清了)、sklearn matplotlib

自动登录

在写以前呢,先大体看一下它的结构

学生利用python破解验证码,模拟登录教务处查看成绩、抢课!

解释一下,cache下面存放的是验证码,ImageIdentification下面的图像处理+识别的相关函数 model下存放的是训练好的结果,network下是关于网络请求的一些类。在写的过程中用了一点点面向对象的思想所以,抽象出一个config类,通过方正系统的一个分析,他在页面里隐藏着很重要的一个数据叫做__VIEWSTATE,在每次请求中都要用到,所以config的代码如下:

# encoding=utf-8[/align]import requests
from bs4 import BeautifulSoup
import urllib
class config(object):
 '''
 抽象出的父类
 '''
 def __init__(self,url):
 self.ip="xxx.xxx.xxx.xxx"
 self.url=url.format(self.ip)
 self.headers = {
 'Accept': 'text/html,application/xhtml+xm…plication/xml;q=0.9,*/*;q=0.8',
 'Accept-Encoding': 'gzip, deflate',
 'Cache-Control': 'no-cache',
 'Connection': 'keep-alive',
 'Content-Type': 'application/x-www-form-urlencoded',
 'Host': self.ip,
 'Pragma': 'no-cache',
 'Referer': self.url,
 'Upgrade-Insecure-Requests': '1',
 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0'
 }
 def getVaules(self,cookies=''):
 html = requests.get(self.url,headers=self.headers,cookies=cookies)
 soup = BeautifulSoup(html.content, 'html.parser', from_encoding='gbk')
 __Value = soup.find('input', {'type': 'hidden', 'name': '__VIEWSTATE'})
 return urllib.quote_plus(__Value.get('value'))

在登录的过程中肯定需要cookies,那么cookies怎么获取,才能使验证码不报错呢?这个也很简单,在获取验证码时,同时获取到验证码的cookies,在登录时填入验证码的cookies就可以实现。代码如下

# encoding=utf-8
from BaseClass import config
import requests
class cookie(config):
 def getcookies(self):
 content=requests.get(self.url,headers=self.headers)
 with open('./cache/yzm.png', 'wb') as f:
 f.write(content.content)
 return content.cookies

前面铺垫了那么多,终于要写登录了,登录是不是要先抓包!抓到请求参数:__VIEWSTATE={}&txtUserName={}&Textbox1=&TextBox2={}&txtSecretCode={}&RadioButtonList1=%D1%A7%C9%FA&Button1=&lbLanguage=&hidPdrs=&hidsc=

__VIEWSTATE:这个参数在网页中已经有了,只需要解析出来,就行了。

txtUserName:这个参数代表 学号

TextBox2:表示密码

txtSecretCode:表示验证码

RadioButtonList1:这个后面解码出来,代表着学生(gbk编码),

代码如下

# encoding=utf-8
import requests
from BaseClass import config
from bs4 import BeautifulSoup
import urllib
class login(config):
 def __init__(self,url):
 self.data = '''__VIEWSTATE={}&txtUserName={}&Textbox1=&TextBox2={}&txtSecretCode={}&RadioButtonList1=%D1%A7%C9%FA&Button1=&lbLanguage=&hidPdrs=&hidsc='''
 super(login,self).__init__(url)
 def login(self,xh,pwd,yzm,cookies):
 try:
 data=self.data.format(self.getVaules(cookies=cookies),xh, pwd, yzm)
 s=requests.session()
 s.cookies=cookies
 con = s.post(self.url, headers=self.headers, data=data)
 if con.url==self.url:
 print("验证码可能出现错误!请重新登陆")
 #print(con.content.decode('gbk'))
 return False,None,None,None,
 else:
 data=con.content
 soup=BeautifulSoup(data,'html.parser',from_encoding='gbk')
 xm=soup.find('span',attrs={'id':'xhxm'}).text[0:len(soup.find('span',attrs={'id':'xhxm'}))-3]
 #print(xm)
 return True,cookies,xh,xm
 except Exception, e:
 print(e.args)
 print(e.message)
 print e.__doc__
 print(u"出现错误!请重新登陆")
 return False,None,None,None,

图像处理代码

# encoding=utf-8
from PIL import Image,ImageFilter
def process():
 file_path='./cache/yzm.png'
 split_lines = [5,17,29,41,53]
 img=Image.open(file_path)
 img = img.convert('RGB')
 r, g, b = img.split()
 image_b_median = b.filter(ImageFilter.MedianFilter())
 image_b_median_binary = image_b_median.point(lambda i: i > 160, mode='1')
 c = 1
 for x_min, x_max in zip(split_lines[:-1], split_lines[1:]):
 image_b_median_binary.crop([x_min, 0, x_max, 22]).save('./cache/yzm-{}.png'.format(c))
 c = c + 1
 print(u"图片处理完成")

预测代码

# encoding=utf-8
from sklearn.externals import joblib
from PIL import Image
import numpy as np
def predict():
 photo_path='./cache/yzm-{}.png'
 X = []
 for i in range(1,5):
 img = Image.open(photo_path.format(i))
 ls = np.array(img).tostring()
 ls=np.fromstring(ls,dtype=bool)
 X.append(ls)
 file_path = './model/knn.pkl'
 knn=joblib.load(file_path)
 ls=knn.predict(X)
 return "".join(ls)

猜你喜欢

转载自blog.csdn.net/qq_41841569/article/details/83111607