用户
搜索
  • TA的每日心情
    奋斗
    昨天 15:12
  • 签到天数: 130 天

    连续签到: 1 天

    [LV.7]常住居民III

    i春秋作家

    Rank: 7Rank: 7Rank: 7

    4

    主题

    87

    帖子

    940

    魔法币
    收听
    3
    粉丝
    1
    注册时间
    2016-8-21

    i春秋签约作者春秋文阁

    发表于 2018-1-25 16:05:45 456534
    本帖最后由 hlpureboy 于 2018-1-25 16:16 编辑

    说明:首先这篇帖子适合入门的同学学习,其次呢,水平有限,若有疏漏之处,在评论区指正一下下哈


    正式进入主题,每学期末都要抢课,学校的服务器还贼渣。先说一个简单的的方法,抓包,不断地发起选课请求,但有一个明显的缺点,那就是cookies容易过期。还得重新登陆替换cookies。于是,就有了今天要分享的内容。其大概分为两个部分:1.自动登录教务处;2.查看成绩、抢课.考虑到有些童鞋没有图像处理的经验,我会把训练好的结果直接给大家。今天先写第一个自动登录。

    自动登录教务处

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

    验证码识别

    1. 想要识别验证码,最起码知道验证码的url才能下载下来。其url地址:http://{}/CheckCode.aspx  {}代表着相应的域名或ip地址。

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



    1.jpg

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

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

    2.png

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

    3.png

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

    4.png

    灰度直方图

    5.png

    二值化之后的图像


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



    6.png

    效果图

    7.png

    全部分割完成





         3.5 将得到的字符串与正确的验证码用机器学习中的KNN算法进行训练,当然也可以用RNN等算法,它的精确度什么的统统没计算,感觉准确度在80%左右。我的小破笔记本跑不了很多数据,见谅呀!
    当然,你也可以采用不同的算法进行训练,其性能什么的可以做一下比对。得到结果集,保存出来,为下一次预测准备。放心吧,得到的结果以附件的形式发出来的。直接拿来用就好了。

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

    自动登录

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

    8.png


    解释一下,cache下面存放的是验证码,ImageIdentification下面的图像处理+识别的相关函数 model下存放的是训练好的结果,network下是关于网络请求的一些类。在写的过程中用了一点点面向对象的思想所以,抽象出一个config类,通过方正系统的一个分析,他在页面里隐藏着很重要的一个数据叫做__VIEWSTATE,在每次请求中都要用到,所以config的代码如下:
    [Python] 纯文本查看 复制代码
    # 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就可以实现。代码如下
    [Python] 纯文本查看 复制代码
    # 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编码),
    代码如下
    [Python] 纯文本查看 复制代码
    # 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,
    手动分割-------------------------------------------------------------------------------------------
    图像处理代码
    [Python] 纯文本查看 复制代码
    # 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"图片处理完成")
    手动分割-------------------------------------------------------------------------------------------
    预测代码
    [Python] 纯文本查看 复制代码
    # 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)
        
    手动分割-------------------------------------------------------------------------------------------
    今天写到这里,在附件里,结果集也在分为64位的和32位的。一天没吃饭有点小饿,先吃饭去。
    游客,如果您要查看本帖隐藏内容请回复


    评分

    参与人数 1魔法币 +3 收起 理由
    cru5h + 3 感谢发布原创作品,i春秋论坛因你更精彩!.

    查看全部评分

    发表于 2018-1-27 20:00:43
    icqcb0cfcf1 发表于 2018-1-26 22:47
    好高深 看不懂啊0.0

    好好看看其实没什么难度
    使用道具 举报 回复
    111111111111111111111111111111111111111111111111111
    使用道具 举报 回复
    鸭子 i春秋-见习白帽 一只深造学习的鸭(深度发
    推荐
    发表于 2018-1-25 21:36:36
    66666666666666666666666666666666666666
    追求自由,自律 学习<strong><font color=&quot;Red&quot;>
    使用道具 举报 回复
    我会说6666666666666666666666666666666
    使用道具 举报 回复
    发表于 2018-1-25 19:50:09
    非常好的一篇文章,改天深入了解机器学习
    使用道具 举报 回复
    6666666666666,看看源码,好好学习一把
    使用道具 举报 回复
    厉害了,以后不怕抢不到课了
    使用道具 举报 回复
    哇塞,是真的可以吗?
    使用道具 举报 回复
    发表于 2018-1-25 19:04:32
    这就是大佬吧!!!
    求知若饥,虚心若愚。
    使用道具 举报 回复
    发表于 2018-1-25 19:38:45
    厉害了,以后不怕抢不到课了
    使用道具 举报 回复
    感谢楼主分享
    使用道具 举报 回复
    发表于 2018-1-25 20:00:26
    see!!!
    使用道具 举报 回复
    发表于 2018-1-25 20:34:34
    谢谢楼主分享
    使用道具 举报 回复
    发表于 2018-1-26 00:32:48
    抢课去了
    使用道具 举报 回复
    666,,,感谢分享
    使用道具 举报 回复
    666666666666
    使用道具 举报 回复
    发表于 2018-1-26 08:26:35
    牛逼啊马飞!
    使用道具 举报 回复
    发表于 2018-1-26 08:26:54
    66666666666666666666666666贼6
    使用道具 举报 回复
    1234下一页
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册