python模拟登陆urp教务处选课&抓取课表

!!!选课功能已添加!!!

本文地址
csdn
前段时间小编写了一篇利用爬虫做词云分析的帖子,有粉丝反馈说想进一步学习爬虫,所以小编今天就用爬虫模拟登陆学校的教务处为例和大家共同学习。坊间有传言说好多同学们学会爬虫后,第一个最想爬取的或者说第一个最想练手的网站就是学校的教务处系统,我相信这也是计算机类专业学生都想做的事儿吧?!

思路解析:

A 、先打开登陆页面,获取cookies;B、再访问验证码的地址,因为验证码是动态的,每次打开都是不同的,所以我们需要保存之前的cookie,保证获取的验证码和后续要提交的表单是同步的。C、然后就是识别验证码的环节,登陆成功后为了避免网页的重定向,所以还需要用requests的session函数禁止重定向。D、构建post表单请求数据,然后将数据提交给网站 F、获取响应头信息,通过返回的网页内容来判断是否登陆成功。

一、模拟登陆

在开题之前,先带大家认识一下:浏览器请求网页的流程。
在web应用中,服务器把网页传给浏览器,实际上就是把网页的HTML发送给浏览器。但是在没有携带cookie的情况下,如果IP短时间高并发的请求网站,该IP就会被封。这里解释一下cookie,cookie是一种回话机制,可以用来存储很多信息,也经常用于反爬。我们一般处理cookie有两种方法:1、cookie的保存 2、cookie的读取。然后登陆部分的处理通常采用的方法就是将爬虫模拟成浏览器,有:1、通过opener添加headers 2、通过requests添加headers 3、批量添加headers 。小编采用的是第二种方法。

用浏览器打开教务处网页的界面如图:
login.PNG

上面提到的headers,cookie等参数的获取,也是有两种方法获取。1、在登陆页面按F12进入开发者模式,选择network,再选中preserve log,选中login页面 ,如图操作:
requests.png

给大家解释下上图的主要信息,在伪装浏览器部分中,重点是获取请求的头部信息和服务器返回的响应头(response headers)。
1 request url : 是浏览器真实请求的域名地址
2 accept :告诉服务器自己接受什么类型
3 accept language:浏览器所希望的语言种类,当服务器能够提供一种以上的语言版本时要用到
4 Connection 表示是否持久连接。如果后面的value值为 ”keep alive“,或者看到请求使用的是Http1.1(默认进行持久连接)
5 host 初始 url 中的主机端口
6 User-Agent 浏览器类型

浏览器向服务器提交的内容的获取:

我们可以故意输错账号或密码 得到提交的表单信息 ,可以通过进入开发者工具或者fiddler得到表单信息 。如下图:
post.PNG

第二种方法就是通过fiddler抓包分析(简单粗暴),个人比较喜欢。(有关 fiddler 的用法,小编会随后为大家更新)

话不多说,给大家上代码:

import requests
import http.cookiejar
from PIL import Image
from bs4 import BeautifulSoup
#导包
cookies = {} #构建一个空字典用来存放cookies
#伪装成浏览器进行网页请求
headers = {
    'Connection': 'Keep-Alive',
    'Accept-Language': 'zh-CN,zh;q=0.8',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0',
   'Accept-Encoding': 'gzip, deflate',
   'Upgrade-Insecure-Requests':'1',
    'Referer': 'http://172******8******',
    'X-Requested-With': 'XMLHttpRequest',
    'Host': '172.*********',
}

#
#
#构建提交表单
def login(username, password, code):
    url = 'http://172.************/loginAction.do'
    form = {
        'zjh1': '',
        'tips': '',
        'lx': '',
        'evalue': '',
        'eflag': '',
        'fs': '',
        'dzslh': '',
        'zjh': username,
        'mm': password,
        'v_yzm': code
    }
    resp = requests.post(url, headers=headers, data=form, cookies=cookies)


写到这里,实在是忍不住要吐槽urp教务系统,代码写得像**一样,小编在看源码时就看懂一个参数“mm”=密码,其他的参数,,,,,,

验证码的识别

一般来讲,验证码的识别有三种方法:
1 人工识别
2 调用tesseract-ocr,自动识别
3 接入付费接口进行识别

这里小编采用的是人工识别,我尝试了tesseract的pillow库来识别,额,,,,,效果嘛,因为是免费的,所以识别的成功率一言难尽啊。数字“2”和英文字母“Z”分不清楚,“N”和"M“也容易混淆,特别是字母”q",我也真的是醉了,给大家看下我们教务系统的验证码
checkcode.jpg

没有经过任何的噪声处理,成功率仅为百分之25.真的是 # 很无语 #。
再给大家看一下识别的案例(为了提高识别率,做了灰度处理):
案例.png

思路就是将验证码保存到本地,然后再调用PIL的image库,把验证码呈现出来,手动输入,完成表单的提交。其实我更想爬取所有的验证码,然后利用神经网络和机器学习做一个训练集,进行自动识别。

imgurl = '验证码图片的请求链接'
mysession = requests.Session()
html = mysession.get(imgurl,timeout=60*4)
checkcode = mysession.get(imgurl,timeout=60*4)
with open('checkcode.png','wb') as f:
    f.write(checkcode.content)
check_img = Image.open("checkcode.png")
check_img.show()
v_yzm = input("code:")

然后我们就可以通过页面返回内容来判断是否登陆成功,小编选取的是课表查询

#课表查询
def get_classinfo():
    url = 'http://172.20.139.153/xkAction.do?actionType=6'
    resp = requests.get(url, headers=headers, cookies=cookies)
    soup = BeautifulSoup(resp.text,'lxml') 
    class = soup.find_all("td")
    print(class)

选课的过程跟小编前段时间做的我校图书馆选座的流程差不多,也是提交一系列的表单

!!!!选课
def ch_class(clanum):
    url = "http://172.@*0.1##.153/xkAction.do?"
   # resp = requests.get(url,headers = headers,cookies = cookies)
    form_1= {
            'actionType':'2',
            'pageNumber':'-1',
            'oper 1':'ori'
            }
    form_2 = {
            'kch':clanum,
            'actionType':'2',
            'oper2':'gl',
            'pageNumber' :'-1'
            }
    form_3={
            'kch':clanum + '_01',
            'preActionType':'2',
            'actionType':'9'
            }
    url_1 = 'http://172**.1*3/xkAction.do?@@2*8*'
    response = requests.post(url,data = form_1,cookies = cookies)
    responce = requests.post(url_1,data = form_2,cookies = cookies,allow_redirects=False)
    soup = BeautifulSoup(responce.content,'lxml')
    pagecon=soup.find("strong")     #检测是否选课成功,可以用bool判断
#大家可以在这里增加死循环,不停的提交表单,直到输出不为空
    print(pagecon)

爬取结果如图:
(ps:这是没有经过字符串处理的,后续小编会系统化输出结果以及完善成绩查询和选课内容)


mmexport1536506596352.jpg

代码写得有点恶心,希望大家多多指教。

你可能感兴趣的:(python模拟登陆urp教务处选课&抓取课表)