关闭

Python 模拟登陆教务选课系统

标签: python模拟登陆验证码抓包win8
2932人阅读 评论(1) 收藏 举报
分类:

前言

本来,可爱的教务选课系统从出生就没有验证码的,但快到选课的时候,突然有验证码了,只好重写一次登陆模块。这次在win8.1系统下写,打造IDE和其他各种库的安装弄了好久,实际抓包写代码的时间不长。


编程环境 及 其他准备

python 2.7
sublime text 3 & JEDI
PIL
chrome
wireshark
(安装和配置请自行搜索)

开始抓包

chrome打开选课系统页面:
登陆页面

分析抓到的包:
登陆页面的包

获取关键点:
GET方法,但是没有带参数。需要cookie。

验证码怎么办呢?看看源代码里有没有图片地址,如果有。直接下载下来就简单了。
页面代码
然而并没有直接的地址,似乎是动态生成的。
看到点击会调用changePic(this)函数,肯定就会发包来获取新的图片,那么我们把它抓下来看看。

点击验证码更换验证码,抓包:
验证码的包
获取地址:
验证码地址
获取关键点:
GET方法,有一个参数v。需要cookie,并且与打开主页的是相同的。

至此可以写出获取验证码图片的代码:

#-*- coding:utf-8 -*-

import urllib,urllib2
import cookielib

class Login(object):
    #构造函数
    def __init__(self):
        super(Login, self).__init__()
        print r"初始化中..."
        #jid即是cookie
        self.jid = ''
    #获取cookie
    def getCookie(self):
        #创建CookieJar对象,自动管理cookie,可迭代
        ck = cookielib.CookieJar()
        #创建类内部对象opener,把CookieJar塞进去,每次打开页面都会自动使用cookie
        self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(ck))
        try:
            #打开登陆页面,获取cookie
            self.opener.open('http://XXX.Mosaic.XXX.XXX/elect')
        except urllib2.URLError,e:
            print "Error code:", e.code
            print "Return content", e.read()
            return None
        for item in ck:
            #将cookie存到类内部变量jid中。
            self.jid = item.name+'='+item.value
            return self.jid
        return None
    #获取验证码
    def getCAPTCHA(self, cookie):
        #输出cookie检查
        print self.jid
        #按照包内格式,写好头部,是一个字典类型对象。
        header = {
            'Accept':'image/webp,*/*;q=0.8',\
            'Accept-Encoding':'gzip, deflate, sdch',\
            'Accept-Language':'zh-CN,zh;q=0.8',\
            'Connection':'keep-alive',
            #cookie的值使用self.jid
            'Cookie':self.jid,\
            'Host':'XXX.Mosaic.XXX.XXX',\
            'Referer':'http://XXX.Mosaic.XXX.XXX/elect/',\
            'User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.130 Safari/537.36'}
        #随机数既然是随机的,服务器也应该不知道是什么,所以这里随便给一个。
        #并且,随机数的值并没有和图片绑定,可以说是然并卵。
        #编码参数`v`
        params = urllib.urlencode({'v':'0.1932646029163152'})
        #构造`GET`的地址,格式为:`服务器地址`+`?`+`编码后的参数`
        capurl = ('http://XXX.Mosaic.XXX.XXX/elect/login/code?%s' % params)
        #用opener打开页面,加上头部
        response = self.opener.open(urllib2.Request(capurl,headers=header))
        #response就是图片内容,将它写入本地图片文件中
        f = file("code.jpg",'wb')
        f.write(response.read())
        f.close()
        #关闭图片,之后可以在其他函数中用绝对路径打开图片。
        return 

验证码获取后,就可以用Image库打开,人眼识别后手动输入。

登陆

还是先抓包吧,用浏览器正常登陆后,抓包分析:
登陆的包
获取关键点:
POST方法,有6个POST DATA。账号密码都是明文传输。j_code就是验证码,也是明文。使用了cookie,并且需要和获取验证码图片时的cookie一样。
仿写包并发送,整体代码如下:

#获取sid,上面那块代码有小更改
#-*- coding:utf-8 -*-

import urllib,urllib2
import cookielib
import Image

class Login(object):
    """save sid and cookie"""
    def __init__(self):
        super(Login, self).__init__()
        print r"初始化中..."
        self.sid = ''
        self.jid = ''
    #获取cookie
    def getCookie(self):
        #创建CookieJar对象,自动管理cookie,可迭代
        ck = cookielib.CookieJar()
        #创建类内部对象opener,把CookieJar塞进去,每次打开页面都会自动使用cookie
        self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(ck))
        try:
            #打开登陆页面,获取cookie
            self.opener.open('http://XXX.Mosaic.XXX.XXX/elect')
        except urllib2.URLError,e:
            print "Error code:", e.code
            print "Return content", e.read()
            return None
        for item in ck:
            #将cookie存到类内部变量jid中。
            self.jid = item.name+'='+item.value
            return self.jid
        return None
    #获取验证码
    def getCAPTCHA(self, cookie):
        #输出cookie检查
        print self.jid
        #按照包内格式,写好头部,是一个字典类型对象。
        header = {
            'Accept':'image/webp,*/*;q=0.8',\
            'Accept-Encoding':'gzip, deflate, sdch',\
            'Accept-Language':'zh-CN,zh;q=0.8',\
            'Connection':'keep-alive',
            #cookie的值使用self.jid
            'Cookie':self.jid,\
            'Host':'XXX.Mosaic.XXX.XXX',\
            'Referer':'http://XXX.Mosaic.XXX.XXX/elect/',\
            'User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.130 Safari/537.36'}
        #随机数既然是随机的,服务器也应该不知道是什么,所以这里随便给一个。
        #并且,随机数的值并没有和图片绑定,可以说是然并卵。
        #编码参数`v`
        params = urllib.urlencode({'v':'0.1932646029163152'})
        #构造`GET`的地址,格式为:`服务器地址`+`?`+`编码后的参数`
        capurl = ('http://XXX.Mosaic.XXX.XXX/elect/login/code?%s' % params)
        #用opener打开页面,加上头部
        response = self.opener.open(urllib2.Request(capurl,headers=header))
        #response就是图片内容,将它写入本地图片文件中
        f = file("code.jpg",'wb')
        f.write(response.read())
        f.close()
        #关闭图片,之后可以在其他函数中用绝对路径打开图片。
        return 

    #获取sid,因为后面选课的时候要用,获取到了说明登陆成功。
    #传入账号,密码,验证码。
    def getSid(self,username,password,j_code):
        #build header
        header = {
            'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',\
            'Accept-Encoding':'gzip, deflate',\
            'Accept-Language':'zh-CN,zh;q=0.8',\
            'Cache-Control':'max-age=0',\
            'Connection':'keep-alive',\
            'Content-Length':'80',\
            'Content-Type':'application/x-www-form-urlencoded',\
            'Cookie':self.jid,\
            'Host':'XXX.Mosaic.XXX.XXX',\
            'Origin':'http://XXX.Mosaic.XXX.XXX',\
            'Referer':'http://XXX.Mosaic.XXX.XXX/elect/index.html',\
            'User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.130 Safari/537.36',\
            }

        #build post data
        #后三个直接照抄
        postData = {'username':username,\
                'password':password,\
                'j_code':j_code,\
                'lt':'',\
                '_eventId':'submit',\
                'gateway':'true',\
                }
        #编码postdata
        postData = urllib.urlencode(postData)
        #目标服务器地址
        posturl = 'http://XXX.Mosaic.XXX.XXX/elect/login'
        #构建request
        request = urllib2.Request(posturl,postData,header)
        #用带有cookie的opener打开
        response = self.opener.open(request)
        #分析返回的地址,`geturl()`就是这么用的。从中提取`sid`并储存。
        string = str(response.geturl())
        self.sid = string[string.find(r'sid=')+4:]
        return self.sid

if __name__ == '__main__':
    #创建类对象
    lo = Login()
    #获取验证码
    j_code = lo.getCAPTCHA(lo.getCookie())
    #打开验证码
    Image.open('code.jpg').show()
    #输入信息
    j_code = raw_input(r"输入看到的验证码:")
    username = raw_input('username:')
    password = raw_input('password:')
    #获取sid并输出,证明登陆成功。
    print lo.getSid(username, password, j_code)

运行效果:
运行效果
账号密码打码了- -,如果不想明文输入密码,可以用getpass库。


后记

为防止被人肉,网址和账号密码等都打码了,包括代码里面的,因此代码是不能直接运行的。
有一段时间一直登陆不上,500错误,就是被服务器拒绝。通过wireshark抓包后对比发现,self.jid写成了jid,所以头部的cookie是空的,把他加上就行了。
还没有写上异常处理,打开网页的地方出错较多,用urllib2.URLError异常类就行了。
有问题或吐槽可以留言,谢谢大家。

2
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:29361次
    • 积分:527
    • 等级:
    • 排名:千里之外
    • 原创:22篇
    • 转载:1篇
    • 译文:0篇
    • 评论:14条
    文章分类
    最新评论