Python携带Cookie登入教务系统

一时兴起学习了Python爬虫,于是马上想到了要爬教务的课表。当然,教务登录必须需要用获取到的Cookie去请求才能登录成功,还会有变态的验证码妨碍自动登录,但是登录过程实现还是比较简单的。

准备工作

  • Python环境搭建
  • 学习Python基本语法
  • 了解整个过程的逻辑和需要的依赖

Python环境搭建就不多说了,Windows下安装Python,再安装PyCharm新建项目,学习一些基本的操作和Python基本语法。

这次我们用到的是Python下强大的爬虫html解析器BeautifulSoup4

Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库。它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式。Beautiful Soup会帮你节省数小时甚至数天的工作时间。

那么首先,我们来了解一下教务的登录方式,对登录过程进行分析,以下使用Fiddler进行抓包。

访问 http://jwgl3.jmu.edu.cn/ ,我们可以看到请求的原始数据如图所示。

qq%e6%88%aa%e5%9b%be20161028173135

浏览器向 http://jwgl3.jmu.edu.cn/ 发送了一个Get请求,得到了200 OK的状态码,请求过程结束。

这个请求的Header(头部)里共有10条参数,分别是Host、Connection、Cache-Control、(*)Accept、Upgrade-Insecure-Requests、User-Agent、DNT、(*)Accept-Encoding、Accept-Language、(*)Cookie

(红色加*号标注的为重要参数,会在后面登录请求中用到,接下来会逐条说明。)

我们看到这个请求OK后我们得到了一个名为ASP.NET_SessionCookie,那么Cookie是什么呢?

Cookie,有时也用其复数形式 Cookies,指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密)。

所以本次请求有两个目的,一是为了获取登录页面,二是为了让服务器给这个请求下发一个身份,在后面的请求中要使用这个Cookie辨认身份。

接下来我们来看一下基本的登录需要什么。

qq%e5%9b%be%e7%89%8720161028175735

可以看见,显示在外的输入共有3个,用户名、密码、验证码,也就是登录至少需要的3个值。

但是按照经验来看,页面内必定包含着隐藏值的验证,那么我们打开页面来找一下有没有其他的Input。

这里说一些html的基础知识,html拥有form标签,在进行数据提交时,在此标签内的input会将其值以POST的形式提交到对应地址。

qq%e5%9b%be%e7%89%8720161028180151

此处有两个隐藏了的输入,分别是__LASTFOCUS__VIEWSTATE,那么我们在之后的请求中要记得将这两个值一起传出。

观察LastFocus和ViewState的值,发现LastFocus为空,而ViewState其在每次访问页面的时候都会变化。所以之后每次请求都要拿下ViewState这个值。

qq%e6%88%aa%e5%9b%be20161028180617

接着还有一个名为BtnLoginImage的输入,这个代表的是界面上的“登录系统”按钮,也将作为一个值POST。

qq%e5%9b%be%e7%89%8720161028180151

qq%e6%88%aa%e5%9b%be20161028182348

我们发现,浏览器还请求了一个/Common/CheckCode.aspx ,我们手动打开这个网址发现这是请求验证码的地址,并且请求是携带着Cookie去请求的,那么在之后请求验证码的过程中我们也要带着Cookie去请求。

保险起见,我们先进行一次登录过程的抓包,看看到底给服务器POST了哪些数据。

qq%e6%88%aa%e5%9b%be20161028183549

一共POST了6条数据,名字如图所示。现在我们可以开始构建请求

我们定义主地址、用户名、密码,并且用BeautifulSoup对获取的页面进行了解析,获取VIEWSTATE的值。

# -*- coding: utf-8 -*-
import urllib.request, requests, http.cookiejar, urllib, re, os
from PIL import Image
from bs4 import BeautifulSoup

home_url = "http://jwgl3.jmu.edu.cn/Login.aspx"
home_page = BeautifulSoup(urllib.request.urlopen(home_url), "html.parser", from_encoding="gb2312")
get_viewstate = (home_page.find_all("input", id="__VIEWSTATE")[0])["value"]

# 用户信息
username = 'xxxxxx'
password = 'xxx'

接着,使用CookieJar统一管理Cookie携带Cookie请求验证码并弹出让用户手动输入。

# 携带Cookie获取验证码并保留在CookieJar中管理
captcha_url = "http://jwgl3.jmu.edu.cn/Common/CheckCode.aspx"
cookie = http.cookiejar.CookieJar()
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookie), urllib.request.HTTPHandler)
urllib.request.install_opener(opener)
captcha = opener.open(captcha_url).read()
local = open('./captcha.tif', 'wb')
local.write(captcha)
local.close()
img = Image.open("./captcha.tif")
img.show()
CheckCode = input('输入验证码: ')

接下来创建需要POST的数据和POST头数据。

# 创建post数据
post_data = urllib.parse.urlencode({
    '__VIEWSTATE': get_viewstate,
    'TxtUserName': username,
    'TxtPassword': password,
    'TxtVerifCode': CheckCode,
    'BtnLoginImage.x': '0',
    'BtnLoginImage.y': '0'
})
post_data = post_data.encode('utf-8')
# 创建header数据,禁止gzip压缩,防止解码问题
headers = dict({
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Referer': 'http://jwgl3.jmu.edu.cn/Login.aspx',
})

这里说明一下头数据包含的东西。

Accept代表浏览器告诉服务器我能接受什么样的数据;

Referer代表浏览器告诉服务器我是从哪个页面过来的;

接下来利用urllib.request库来构建一个完整的请求,并进行登录是否成功的判断

# 构建请求,模拟登录post
login_request = urllib.request.Request(home_url, data=post_data, headers=headers)
login_response = urllib.request.urlopen(login_request)
login_status = login_response.read()

# 解析post后页面,判断是否登录
login_page = BeautifulSoup(login_status, "html.parser")
get_title = str(login_page.find_all("title")[0].get_text(strip=True))
if get_title == "集美大学综合教务管理系统":
    print("You Are Now Logged In !!!")
    flag = 1
else:
    print("Log In FAILED.")
    print("Please Retry to Log In.")
    flag = 0

整个登录过程到此结束。

还有一个Header参数我们没有说,那就是Accept-Encording

这个请求是告诉服务器我是否能接受页面压缩,在这里我们在请求中并没有写,是经过测试后发现页面被gzip压缩,导致乱码无法正常解析,所以不使用这个参数。


已发布

分类

作者:

标签

评论

《“Python携带Cookie登入教务系统”》 有 1 条评论

  1. Cal 的头像
    Cal

    😮