本章内容包含python模拟登录中国海洋大学教务系统(青果)- 百度智能云识别验证码 - 进入选课页面。

系列文章目录

第一章 python模拟登录中国海洋大学教务系统(青果)
第二章 爬取学期所有专业课至excel
第三章 课表排课


文章目录

  • 系列文章目录
  • 前言
  • 一、模拟登录
    • 1.分析提交表单
    • 2.百度智能云识别验证码
    • 3.代码
  • 二、进入选课页面
  • 三、完整代码及代码效果
  • 四、遇到的问题
  • 总结

前言

提示:本人是个菜鸟,没系统学过python、html等,对以下所有知识点只会应用,不懂原理,大家可以去看看这两位大佬的技术文章。

python爬虫模拟登录学校教务系统(青果教务系统)并查询个人成绩——王森ouc
python-scrapy模拟登陆网站–登陆青果教务管理系统(一)——耿子666

本文是借鉴了以上两位大佬的文章,能够跑出结果,但我不是很懂原理,会在网上整理总结,仅供参考。


一、模拟登录

这个前两个大佬都做的很优秀了,我一开始只会f12,查看一下要提交的表单,然后发现提交表单的key(不知道专业术语是啥)会变,我就歇菜了。
就下面这个⬇ , _uydvv,_pydvv,它们是由_u,_p和你输入的验证码拼接而成的

之后查资料的时候,发现竟然有大佬已经写了我想写的前半部分内容,整挺好,然后踩在大佬的肩膀上,修修改改也写了一天,才基本实现了所有内容。
现在我就带着大家再挨个走一遍所有的路程,出发!

1.分析提交表单

(海大的教务系统需要连校园网或VPN)
1.使用Google Chrome打开教务网站http://jwgl.ouc.edu.cn/cas/login.action

2.按F12 - 进入开发者工具
点击Network - 网络

chrome开发者工具最常用的四个功能模块:元素(ELements)、控制台(Console)、源代码(Sources),网络(Network)。

勾选Preserve log - 保留请求日志

谷歌开发者工具里面这个preserve log :保留请求日志,跳转页面的时候勾选上,可以看到跳转前的请求,也可适用于chrome开发者工具抓包的问。

3.随便输入一些账户密码验证码
可以看到点击验证码框或验证码的时候,会有名为genValidateCode?..的请求来获取新的验证码图片。

点击该请求(查看请求的详细内容)- 点击preview(预览)-可以看到验证码图片
再点击Headers

Request Method是Get

Request URL: http://jwgl.ouc.edu.cn/cas/genValidateCode?dateTime=Fri%20Jul%2023%202021%2010:35:41%20GMT+0800%20(%D6%D0%B9%FA%B1%EA%D7%BC%CA%B1%BC%E4)

复制该url进行打开,可以看到并不是原来的验证码图片,每次刷新后验证码都不一样

经过验证,该验证码与dateTime并没有关系,目前我还不知道原理,请大佬指教

通过该url可以获得验证码,暂且不管该验证码是否是我们需要的正确的验证码


4.点击提交,出现名为logon.action的请求,点击观察其Headers内容

在写请求的时候,一般形式应该是(url,表单数据,请求头):

response = request.post(url, data, headers)

这些在Headers内容里都能找到,然后就是用代码构造这些内容:

import requests
url = 'http://jwgl.ouc.edu.cn/cas/logon.action'
#表单信息不能直接复制,这里就演示一下,并不是实际实现的
data = {'_u'+randnumber: 'MTgwOTAwMTIwMjg7OzkyODY2QTM4NUI4NDBCMkQzQjFGNEI5MzgwMDI2Qzg3','_p'+randnumber: 'e045dced42fea99c1434f62903a9e564','randnumber': 'y7jz','isPasswordPolicy': '1','txt_mm_expression': '12','txt_mm_length': '11','txt_mm_userzh': '0',
}
#headers里的内容并没有完全复制,我也不清楚哪些是必须的,哪些是非必须的,建议全部粘贴,以下是拷贝大佬的,我就不做修改了
headers = {'Host': 'jwgl.ouc.edu.cn','Origin': 'http://jwgl.ouc.edu.cn','Referer': 'http://jwgl.ouc.edu.cn/cas/login.action','User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36','X-Requested-With': 'XMLHttpRequest','Upgrade-Insecure-Requests': '1',
}
#这里用session,而不是request
r = session.post(url, data=data, headers=headers)

request对象的生命周期是针对一个客户端(说确切点就是一个浏览器应用程序)的一次请求,当请求完毕之后,request里边的内容也将被释放掉 。
而session的生命周期也是针对一个客户端,但是却是在别人设置的会话周期内(一般是20-30分钟),session里边的内容将一直存在,即便关闭了这个客户端浏览器 session也不一定会马上释放掉的。
——参考request和session的区别

在这里因为在登录后,还要跳转到选课页面,需要保存登录信息,所以用session

另外好像可以#创建cookie,利用cookie实现持久化登录,感兴趣的可以瞅瞅

会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。
——参考Cookie和Session详解


表单信息不能直接复制,需要先观察一下

_uy7jz: MTgwOTAwMTIwMjg7OzkyODY2QTM4NUI4NDBCMkQzQjFGNEI5MzgwMDI2Qzg3
_py7jz: e045dced42fea99c1434f62903a9e564
randnumber: y7jz #验证码
isPasswordPolicy: 1#密码合法
txt_mm_expression: 12#密码规则
txt_mm_length: 11#输入的密码长度
txt_mm_userzh: 0

观察得到:
1.前两项的key是_u,_p+输入的验证码,value是加密过的,看不出内容
2.根据变量名猜测其含义,见注释
3.账户密码没有直接显示出来

所以要去源代码里找相关信息:
1.定位账号密码代码的位置
2.在控制台里按CTRL+shift+F打开全局搜索,搜索yhmm

3.点击第二个

4.观察代码:前几行都是获取输入,后几行就是对这些信息的加密,我们需要在代码里对信息进行同样的加密

 password = hex_md5(hex_md5(password)+hex_md5(randnumber.toLowerCase()));var p_username = "_u"+randnumber;var p_password = "_p"+randnumber;username = base64encode(username+";;"+_sessionid);var params = p_username+"="+username+"&"+p_password+"="+password+"&randnumber="+randnumber+"&isPasswordPolicy="+passwordPolicy+"&txt_mm_expression="+txt_mm_expression+"&txt_mm_length="+txt_mm_length+"&txt_mm_userzh="+txt_mm_userzh;

加密语句⬆⬇对应

#具体加密原理见王森ouc大佬的文章password = md5(password.encode('utf-8')).hexdigest()randnumber = md5(randnumber.lower().encode('utf-8')).hexdigest()password = md5((password + randnumber).encode('utf-8')).hexdigest()
#randnumber会在之前通过百度智能云文字识别获得data['randnumber'] = randnumberp_username = '_u' + randnumberp_password = '_p' + randnumberdata[p_username] = usernamedata[p_password] = password
#sessionid是会话的id,一般是存放在cookie中_sessionid = session.cookies.get_dict()['JSESSIONID']username = base64.b64encode(username.encode('utf-8') + b';;' + str(_sessionid).encode('utf-8'))
#params不知道是干啥的,这里没用

⬆⬆⬆以上,账号、密码、验证码、url、data、headers都已分析过


2.百度智能云识别验证码

没有用过百度智能云的可以看看:百度智能云-文字识别SDK-识别验证码Demo

import requests
from aip import AipOcr
from bs4 import BeautifulSoupheaders = {'Host': 'jwgl.ouc.edu.cn','Origin': 'http://jwgl.ouc.edu.cn','Referer': 'http://jwgl.ouc.edu.cn/cas/login.action','User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36','X-Requested-With': 'XMLHttpRequest','Upgrade-Insecure-Requests': '1',
}
#百度智能云-文字识别
def randnumber_ocr(image):APP_ID = ''  # 在百度官网的应用列表中查看APP_IDAPI_KEY = ''  # 在百度官网的应用列表中查看API_KEYSECRET_KEY = ''  # 在百度官网的应用列表中查看SECRET_KEYclient = AipOcr(APP_ID, API_KEY, SECRET_KEY)text = client.basicAccurate(image)if text['words_result_num'] == 1:return text['words_result'][0]['words'].strip()else:return ''def logon():url = 'http://jwgl.ouc.edu.cn/cas/logon.action'session = requests.Session()
#百度智能云-文字识别-获取验证码    randnumber = ''while len(randnumber) != 4:r = session.get('http://jwgl.ouc.edu.cn/cas/genValidateCode', headers=headers)      randnumber = randnumber_ocr(r.content).replace(' ','')#去除空格if __name__ == '__main__':logon()

3.代码

import requests
from aip import AipOcr
import base64
from hashlib import md5
import json
import re
from bs4 import BeautifulSoupheaders = {'Host': 'jwgl.ouc.edu.cn','Origin': 'http://jwgl.ouc.edu.cn','Referer': 'http://jwgl.ouc.edu.cn/cas/login.action','User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36','X-Requested-With': 'XMLHttpRequest','Upgrade-Insecure-Requests': '1',
}
#data和headers一样,并没有传全部的项
data = {'randnumber': 'gqzd'
}
#百度智能云-文字识别
def randnumber_ocr(image):APP_ID = ''  # 在百度官网的应用列表中查看APP_IDAPI_KEY = ''  # 在百度官网的应用列表中查看API_KEYSECRET_KEY = ''  # 在百度官网的应用列表中查看SECRET_KEYclient = AipOcr(APP_ID, API_KEY, SECRET_KEY)text = client.basicAccurate(image)if text['words_result_num'] == 1:return text['words_result'][0]['words'].strip()else:return ''def logon():url = 'http://jwgl.ouc.edu.cn/cas/logon.action'username = ''  # 输入你的用户名,也就是学号password = ''  # 输入你的密码session = requests.Session()
#百度智能云-文字识别-获取验证码    randnumber = ''while len(randnumber) != 4:r = session.get('http://jwgl.ouc.edu.cn/cas/genValidateCode', headers=headers)      randnumber = randnumber_ocr(r.content).replace(' ','')#去除空格
#构造data-信息加密        password = md5(password.encode('utf-8')).hexdigest()randnumber = md5(randnumber.lower().encode('utf-8')).hexdigest()password = md5((password + randnumber).encode('utf-8')).hexdigest()
#randnumber会在之前通过百度智能云文字识别获得data['randnumber'] = randnumberp_username = '_u' + randnumberp_password = '_p' + randnumberdata[p_username] = usernamedata[p_password] = password
#sessionid是会话的id,一般是存放在cookie中_sessionid = session.cookies.get_dict()['JSESSIONID']username = base64.b64encode(username.encode('utf-8') + b';;' + str(_sessionid).encode('utf-8'))
#post    r = session.post(url, data=data, headers=headers)
#response    info = json.loads(r.text)status = info['status']if status == '401':print('验证码错误')returnelif status == '200':passelse:print(info['message'])returnprint('登录成功')if __name__ == '__main__':logon()

二、进入选课页面

登录成功后,就要进入选课页面,此部分与一内容基本相同且更简单,可以自己尝试分析一下


1.选择选课学年学期-年级-专业——点击检索
2.
出现新请求,一般我们需要的都是document类型的,点击查看其详细信息

3.
Request URL: http://jwgl.ouc.edu.cn/taglib/DataTable.jsp?tableId=6146
Request Method: POST

Referer: http://jwgl.ouc.edu.cn/student/wsxk.kcbcx.html?menucode=JW130414

FormData
initQry: 0
xktype: 2 #选课类型
xh: 1*********8 #你的学号
xn: 2021 #学年
xq: 1 #学期-夏0-秋1-春2
nj: 20** #你的年级
zydm: 0**0 #你的专业代码
items:
xnxq: 2021-1 #学年-学期
kcfw: Specialty #课程范围
sel_nj: 2019 #选择的年级2018-2020
sel_zydm: 0011 #选择的专业代码
sel_schoolarea:
sel_cddwdm:
sel_kc:
kcmc:

经过观察,表单信息都很简单,构造data,headers需要有Referer

Referer 是 HTTP 请求header 的一部分,当浏览器(或者模拟浏览器行为)向web 服务器发送请求的时候,头信息里有包含 Referer 。它就是表示该请求的来源。
——参考什么是HTTP Referer?

def get_score(session, sel_nj):url = 'http://jwgl.ouc.edu.cn/taglib/DataTable.jsp?tableId=6146'
#这个data包含了所有项,但有些其实的非必须的formdata={'initQry': '0','xktype': '2',#选课类型'xh': '1**********',#修改为你的学号'xn': '2021',#学年'xq': '1',#学期-夏0-秋1-春2'nj': '20**',#修改为你的年级'zydm': '0**0',#修改为你的专业代码'items': '','xnxq': '2021-1',#学年-学期'kcfw': 'Specialty',#课程范围'sel_nj': sel_nj,#修改为你想选择的年级2018-2020'sel_zydm': '0011',#修改为你想选择的专业代码'sel_schoolarea': '','sel_cddwdm': '','sel_kc': '','kcmc': ''}
#这个headers必须包含Refererheaders['Referer'] = 'http://jwgl.ouc.edu.cn/student/wsxk.kcbcx.html?menucode=JW130414'
#使用sessionr = session.post(url,data=formdata, headers=headers)#解析一下网页,打印一下表格内容看看soup = BeautifulSoup(r.text, 'html.parser')table_node = soup.find_all('td')for table in table_node:print (table.text)session.close()

三、完整代码及代码效果

import requests
from aip import AipOcr
import base64
from hashlib import md5
import json
import re
from bs4 import BeautifulSoupheaders = {'Host': 'jwgl.ouc.edu.cn','Origin': 'http://jwgl.ouc.edu.cn','Referer': 'http://jwgl.ouc.edu.cn/cas/login.action','User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36','X-Requested-With': 'XMLHttpRequest','Upgrade-Insecure-Requests': '1',
}
#data和headers一样,并没有传全部的项
data = {'randnumber': 'gqzd'
}
#百度智能云-文字识别
def randnumber_ocr(image):APP_ID = ''  # 在百度官网的应用列表中查看APP_IDAPI_KEY = ''  # 在百度官网的应用列表中查看API_KEYSECRET_KEY = ''  # 在百度官网的应用列表中查看SECRET_KEYclient = AipOcr(APP_ID, API_KEY, SECRET_KEY)text = client.basicAccurate(image)if text['words_result_num'] == 1:return text['words_result'][0]['words'].strip()else:return ''def get_score(session):url = 'http://jwgl.ouc.edu.cn/taglib/DataTable.jsp?tableId=6146'
#这个data包含了所有项,但有些其实的非必须的formdata={'initQry': '0','xktype': '2',#选课类型'xh': '1**********',#修改为你的学号'xn': '2021',#学年'xq': '1',#学期-夏0-秋1-春2'nj': '20**',#修改为你的年级'zydm': '0**0',#修改为你的专业代码'items': '','xnxq': '2021-1',#学年-学期'kcfw': 'Specialty',#课程范围'sel_nj': '2019',#修改为你想选择的年级2018-2020'sel_zydm': '0011',#修改为你想选择的专业代码'sel_schoolarea': '','sel_cddwdm': '','sel_kc': '','kcmc': ''}
#这个headers必须包含Refererheaders['Referer'] = 'http://jwgl.ouc.edu.cn/student/wsxk.kcbcx.html?menucode=JW130414'
#使用sessionr = session.post(url,data=formdata, headers=headers)#解析一下网页,打印一下表格内容看看soup = BeautifulSoup(r.text, 'html.parser')table_node = soup.find_all('td')for table in table_node:#if table.style != 'none':#有隐藏的列表格,没必要输出print (table.text)session.close()def logon():url = 'http://jwgl.ouc.edu.cn/cas/logon.action'username = ''  # 输入你的用户名,也就是学号password = ''  # 输入你的密码session = requests.Session()
#百度智能云-文字识别-获取验证码    randnumber = ''while len(randnumber) != 4:r = session.get('http://jwgl.ouc.edu.cn/cas/genValidateCode', headers=headers)      randnumber = randnumber_ocr(r.content).replace(' ','')#去除空格
#randnumber会在之前通过百度智能云文字识别获得data['randnumber'] = randnumberp_username = '_u' + randnumberp_password = '_p' + randnumber
#构造data-信息加密        password = md5(password.encode('utf-8')).hexdigest()randnumber = md5(randnumber.lower().encode('utf-8')).hexdigest()password = md5((password + randnumber).encode('utf-8')).hexdigest()
#sessionid是会话的id,一般是存放在cookie中_sessionid = session.cookies.get_dict()['JSESSIONID']username = base64.b64encode(username.encode('utf-8') + b';;' + str(_sessionid).encode('utf-8'))
#构造data    data[p_username] = usernamedata[p_password] = password
#post    r = session.post(url, data=data, headers=headers)
#response    info = json.loads(r.text)status = info['status']if status == '401':print('验证码错误')returnelif status == '200':passelse:print(info['message'])returnprint('登录成功')get_score(session)if __name__ == '__main__':logon()

运行效果:


四、遇到的问题

KeyError: 'words_result_num'

没有填写APP_ID、API_KEY 、SECRET_KEY

    print(tds[1].string + ": " + tds[16].string)
TypeError: can only concatenate str (not "NoneType") to str

爬取错误,tds里没有内容

    if table.attrs['style'] != "display:none;":
KeyError: 'style'
TypeError: 'NoneType' object is not subscriptable
    table = soup.find('td')print (table)#<td id="head_curent_skbjdm" width="6%">选课号</td>print (table['id'])#head_curent_skbjdmprint (table['style'])#KeyError: 'style'print (table.id)#Noneprint (table.style)#None#print (table.style['display'])#TypeError: 'NoneType' object is not subscriptable#print (table.attrs['style'])#KeyError: 'style'

<td id=“tr2_cddw” name=“cddw” style=“display:none;”>计算机科学与技术系</td>
这样一个table,其style=“display:none;”,说明其是隐藏的,没有必要爬取,但是有的table有style,有的没有
所以要怎么添加判断呢 TT 感谢指教

总结

知识点十分多啊,整理了两天,收获也很多 \OoO/

码字不易,感谢点赞评论收藏关注~

python模拟登录中国海洋大学教务系统(青果)- 爬取学期所有专业课至excel - 并进行课表排课(一)相关推荐

  1. JSoup模拟登录新版正方教务系统(内网-教务系统)获取信息过程详解

    新版正方教务系统登录界面: 目录 一.需求分析 二.模拟登录内网 三.模拟登录教务系统 四.爬取成绩和课表信息 参考文章 一.需求分析   需要访问教务系统,爬取出课表成绩等信息,并在自己所写的APP ...

  2. 枯燥的寒假生活(一) python爬虫模拟登录whu老教务系统获取期末考试成绩(已失效 , 老教务系统增加了新的反爬, 老教务系统已停用)

    python模拟登录老教务系统(2021.6.24更新) 一.写在前面 之前用爬虫爬取的都是静态网页html中的内容,但是大多数时候需要动态处理网页爬取数据.因为学校出成绩太慢了,每次都自己打开浏览器 ...

  3. JAVA使用HttpClient模拟登录正方教务系统,爬取学籍信息和课程表成绩等,超详细登录分析和代码注解

    目录 前言 分析 代码实现 第一次GET POST登录 第二次Get 第三次GET 第四次GET 第五次GET 测试 完整代码 前言 最近在做一个APP,需要获取我们学校--武汉纺织大学皇家停水断电断 ...

  4. python模拟登陆川农大教务系统----requests库

    人生苦短,我用python,学了段时间爬虫,该应用下了,不如就拿我们学校教务处开刀呗,心疼我教3秒. 废话不多说,首先先分析下教务系统登陆机制: 先打开谷歌浏览器,登陆川农教务处,按F12,记得把pr ...

  5. 企查查企业详情爬虫(自动模拟登录企业详情页法律风险爬取)

    由于爬取数据涉及到网站会员,没有会员有需求的别多虑,找老板冲啊 读取已有json文件爬取对应公司的企业数据,保存 工具: Chrome 点击下载chrome的webdriver: http://chr ...

  6. 新版正方教务系统Java爬取_正方教务系统成绩爬取(仅个人)+tk可视化

    [JavaScript] 纯文本查看 复制代码var CryptoJS = CryptoJS || function (u, p) { var d = {}, l = d.lib = {}, s = ...

  7. 用java模拟登录正方教务系统,抓取课表和个人成绩等数据

    之前学了一些java web的编程,理解了web应用的原理后,就突然想到,可以用java模拟登录吉珠的教务系统,然后爬取里面的课表.成绩.个人信息等等数据,然后就可以写成一个简易的课表APP. 一.第 ...

  8. 使用python-requests爬虫模拟登陆中国海洋大学教务处网站

    python的第三方库Requests是一个简单而且实用的网络爬虫库,今天,我将为大家演示如何通过requests爬虫实现模拟登录中国海洋大学教务处网站. 程序流程: 1.引入需要的外部库. impo ...

  9. c语言 排课系统 利用栈,C语言-课表排课系统

    功能模块概要说明: 1.输入函数: char* uscanf(int,int,int) //图形模式下输入函数,大小写26个字母0-9数字外加空格键为有效输入,可以使用BACKSPACE. 2.开始界 ...

  10. C语言-课表排课系统

    程序用C语言实现,看文档日期是04年中旬写的.程序有WORD文档但流程图和结构图我拷不上来,我在下面帖一些程序的主要模块.主要函数以及程序操作说明,方面了解程序的整个流程,以供学习: 基本操作: 输入 ...

最新文章

  1. stm32 内部sram大小_在SRAM、FLASH中调试代码的配置方法(附详细步骤)
  2. Matlab内存不足问题的解决 .
  3. C++ 作用域使用规范建议
  4. csync2+sqlite实现数据的高效实时的增量备份
  5. 【李宏毅机器学习】04:梯度下降Gradient Descent
  6. 在doPost,service等方法里配置字符编码过滤器,防止出现中文乱码
  7. 怎样做计算机系统的镜像文件,Windows7 镜像制作过程 图文说明
  8. 无线定位服务器,[浅谈无线定位技术] 无线定位技术有哪些
  9. html reset 无效,HTML中的input type=reset标签失效(不起作用)的可能原因。
  10. 方便的视频播放器-饺子播放器
  11. android 实现微信朋友圈文字收起与全文显示功能
  12. 基于STM32HAL库ADC+DMA模式,高精度采集电池电量与芯片内部温度方法 (48脚 使用内部参考电压方案)
  13. cocoscreator的游戏背景适配方案
  14. Java的字符串连接符(+)
  15. 130行代码实现海贼王漫画下载
  16. SQL批处理与事务控制
  17. 流动电影放映服务器维修,流动数字电影放映机的日常操作与维护
  18. TCP标志位 RST作用、原理、攻击
  19. 日文系统常用词汇[日语]
  20. java swing 知乎_为什么 Java Swing 默认这么丑?

热门文章

  1. avmovie_AVMovie1和AVMovie2
  2. Android发短信功能
  3. ognl以及令牌以及开头的一点方法
  4. P2906 [USACO08OPEN]牛的街区Cow Neighborhoods
  5. 2019各个省会城市全新DNS大全一
  6. 【一起学Rust】Rust介绍与开发环境搭建
  7. 怎么把图片转换成表格?这三种办法值得收藏
  8. C语言如何统计程序运行时间
  9. HyperLynx(二十)DDR(三)DIMM、DD2、DDR3、DDR4和DDR5介绍
  10. 一直以来伴随我的一些学习习惯(part1)