广州python课程_两天时间挑战python实现广州大学抢课?(搜索课程篇)

继续昨天的内容,如果没看第一篇的同学可以进入我的文章查看。今天学校很配合开放了查看课程搜索,给了我抓包的机会,不过抓包后分析的数据弄了很久时间。今天的任务是:进入自主选课,并完成搜索课程。完成的任务结果是这样的:

这就是我们搜索课程 世界电影大师 的返回结果,这些结果数据在提交抢课篇是必须用到的,也就是说能爬到这里的话也就差最后一步提交抢课了。

废话不多说,抓包走一波:

推荐按照我的顺序抓,每一次操作留一段时间来标记下一步操作,最好不要有操作失误,不然抓包数据看起来很乱。

这里先讲一下上一篇没讲的302和200的区分:

假如我们的post请求的是302,它就会不断自动重定向直至出现200的状态码。一般我们只分析返回状态码是200的数据,记住是返回的response数据,发送的request请求除外302重定向

中间一个蓝色圆圈的是网页,显示网页基本内容

js图标的就是js代码,用作动态数据的,比如我们的课程点击搜索才出现在下面用的就是js生成

ok正篇开始:

进入自主选课

charles:

为什么不看第一个post,因为第一个post数据只是返回一个提示,并且没有set-cookie数据,可以略过。这里先看params参数:default多加载几次发现是一样的,su帐号不用说了,

N253512其实是识别你进入自主选课的参数,ctrl+f就出来了,就在我们的系统页面中:

代码:

gnmkdm = re.search(r"\'(.{1,8})\',\'(.{10,50})\',\'自主选课", req.text).groups()

然后看cookie:

和前面不同了,安装上一篇的方法,选到response往上找哪里有set-cookie数据

看到这个cookie跟我们的一样,再仔细看一看,这不是在我们上一篇登录进入系统重定向过程中的一个请求吗,已经自动保存在我们session()里面的,所以cookie不用管。

看一下headers请求头:

发现就是进入系统的页面,用该页面的request.url就可以提取,这里要讲一下怎么知道发送请求的url:

问号后面就是我们要发送的param参数,?号前面的链接就是我们的this_url。这里我的进入自主选课前面的部分链接也是提取出来的,觉得麻烦直接写死也没问题。

代码:

def enter_choose(req):

global enter_choose_num

global ver

gnmkdm = re.search(r"\'(.{1,8})\',\'(.{10,50})\',\'自主选课", req.text).groups()

enter_choose_num = gnmkdm[0]

this_url = 'http://jwxt.gzhu.edu.cn/jwglxt' + gnmkdm[1]

param_data = {

'gnmkdm': gnmkdm[0],

'layout': 'default',

'su': username

}

header['Referer'] = req.url

request = reqs('get', this_url, param_data=param_data)

return request

进入选课页面后,就要进行我们今天的重头戏,搜索课程:

主修课程搜索:

看到表单数据没,看到都想吐,没办法一个一个分析。这里介绍一个工具,不想逐个输入字段名并且你的浏览器是谷歌的话,可以按F12选中该请求右击——copy——copy as cURL(base),然后进入这个网址:https://curl.trillworks.com/

这样请求头,form表单,还有param参数等等所有数据都帮你写好了。咦?等等,这不就可以......嘿嘿

看到这么长的数据随便挑一个最长的搜索把:

很nice仔细对照一下发现里面有一大部分数据都有出现在表单里,而且这请求就是我们进入选课的请求,写个函数,输入字段和请求返回结果。

def get_input_value(id, req):

result = re.search(str(id) + '"' + '.*?value="(.*?)"', req.text).groups()[0]

return result

而另外一大部分的数据在这个请求里:

xkkz_id搜索一下他的值发现在也是在进入选课的页面

xszxztz一样

kspage和jspage找的方法不一样,直接搜索他们的名字:

找到他们的名字在js中它们的初始值为0,看一下这个请求发送了什么

啥也没有,cookie一样,20191204在之前随便一个请求都能获得,再弄一下header指向:

def get_hidden_data_form(req): # 获取kspage和jspage

this_url = 'http://jwxt.gzhu.edu.cn/jwglxt/js/comp/jwglxt/xkgl/xsxk/zzxkYzb.js'

ver = re.search(r'ver=(.*?)"', req.text).groups()[0] # 获取ver的参数

param_data = {

'ver': ver

}

header['Referer'] = req.url

request = reqs('get', this_url, param_data=param_data)

result = json.loads('{"' + re.search(r'kspage\D*\d*\D*\d*', request.text).group() + '}')

return result

def get_hidden_data(req, num): # 获取另一部分form表单请求

this_url = 'http://jwxt.gzhu.edu.cn/jwglxt/xsxk/zzxkyzb_cxZzxkYzbDisplay.html'

page_data = get_hidden_data_form(req)

xkkz_id = search_form_kklxdm(req, num)[1]

form_data = {

'xkkz_id': xkkz_id,

'xszxzt': get_input_value('xszxzt', req),

'kspage': page_data['kspage'],

'jspage': page_data['jspage']

}

param_data = {

'gnmkdm': enter_choose_num,

'su': username

}

header['Referer'] = req.url

request = reqs('post', this_url, param_data=param_data, form_data=form_data)

return page_data, request

最后就剩下这三个数据:

kklxdm:

在js找到kklxdm被赋值为firstKklxdm这个元素的值,搜索该值:

代码:

def search_form_kklxdm(req):

result = re.findall(r'queryCourse.*?,(.*?)\)', req.text)

return eval('[' + result[0] + ']')

kspage和jspage:

看到这堆数据都是我们要的表单数据,kspage就是初始值+1,而jspage=初始值+step,我们在这个js里搜索一下step:

完美,表单数据就这样填满一个了,接下来就弄一下referer指向和param参数:

def search(req): # req 是首页的请求

this_url = 'http://jwxt.gzhu.edu.cn/jwglxt/xsxk/zzxkyzb_cxZzxkYzbPartDisplay.html'

param_data = {

'gnmkdm': enter_choose_num,

'su': username

}

page_data, req2 = get_hidden_data(req) # 获取请求2

kklxdm = search_form_kklxdm(req) # 查找kklxdm

form_data = {

'filter_list[0]': lesson_name, # ok

'xqh_id': get_input_value('xqh_id', req), # ok

'jg_id': get_input_value('jg_id_1', req), # ok-------------

'zyh_id': get_input_value('zyh_id', req), # ok

'zyfx_id': get_input_value('zyfx_id', req), # ok

'njdm_id': get_input_value('njdm_id', req), # ok

'bh_id': get_input_value('bh_id', req), # ok

'xbm': get_input_value('xbm', req), # ok

'xslbdm': get_input_value('xslbdm', req), # ok

'ccdm': get_input_value('ccdm', req), # ok

'xsbj': get_input_value('xsbj', req), # ok

'xkxnm': get_input_value('xkxnm', req), # ok

'xkxqm': get_input_value('xkxqm', req), # ok

'jxbzb': get_input_value('jxbzb', req), # ok

'sfkknj': get_input_value('sfkknj', req2), # ok

'sfkkzy': get_input_value('sfkkzy', req2), # ok

'sfznkx': get_input_value('sfznkx', req2), # ok

'zdkxms': get_input_value('zdkxms', req2), # ok

'sfkxq': get_input_value('sfkxq', req2), # ok

'sfkcfx': get_input_value('sfkcfx', req2), # ok

'kkbk': get_input_value('kkbk', req2), # ok

'kkbkdj': get_input_value('kkbkdj', req2), # ok

'sfkgbcx': get_input_value('sfkgbcx', req2), # ok

'sfrxtgkcxd': get_input_value('sfrxtgkcxd', req2), # ok

'tykczgxdcs': get_input_value('tykczgxdcs', req2), # ok

'rlkz': get_input_value('rlkz', req2), # ok

'rwlx': get_input_value('rwlx', req2), # ok

'xkly': get_input_value('xkly', req2), # ok

'bklx_id': get_input_value('bklx_id', req2), # ok

'kklxdm': kklxdm[0], # ok-------------

'kspage': str(int(page_data['jspage']) + 1), # -------

'jspage': str(int(page_data['jspage']) + 10), # -------

}

header['Referer'] = req.url

request = reqs('post', this_url, param_data=param_data, form_data=form_data)

选修课程搜索:

接下来下一个请求:

一大堆隐藏域,很明显为下一个请求使用的,发送请求:

和之前的请求几乎一样,通过比较只有xkkz_id不同,并且在上面求01时出现过一次该请求:

很明显是区分主修课程和选修课程用的,修改一下刚刚的请求根据不同的选择返回不同的值:

def search_form_kklxdm(req, num):

result = re.findall(r'queryCourse.*?,(.*?)\)', req.text)

if num == 1:

return eval('[' + result[0] + ']')·

else:

return eval('[' + result[1] + ']')

def get_hidden_data(req, num):

this_url = 'http://jwxt.gzhu.edu.cn/jwglxt/xsxk/zzxkyzb_cxZzxkYzbDisplay.html'

page_data = get_hidden_data_form(req)

xkkz_id = search_form_kklxdm(req, num)[1]

form_data = {

'xkkz_id': xkkz_id,

'xszxzt': get_input_value('xszxzt', req),

'kspage': page_data['kspage'],

'jspage': page_data['jspage']

}

param_data = {

'gnmkdm': enter_choose_num,

'su': username

}

header['Referer'] = req.url

request = reqs('post', this_url, param_data=param_data, form_data=form_data)

return page_data, request

下一个请求,对比一下主修课程的form表单,发现字段名基本都相同,只不过的其中一部分需要用到刚刚请求过的隐藏域,修改一下,设置成可以选择主修或者选修课程的不同表单发送:

def search(req):

this_url = 'http://jwxt.gzhu.edu.cn/jwglxt/xsxk/zzxkyzb_cxZzxkYzbPartDisplay.html'

lesson_name = input('\n请输入课程名称:') # ok------------

lesson_choose = input('\n主修课程请按"1",选修课程请按"2":')

param_data = {

'gnmkdm': enter_choose_num,

'su': username

}

if lesson_choose == '1':

page_data, req2 = get_hidden_data(req, 1) # 1就是主修课程

kklxdm = search_form_kklxdm(req, 1)

else:

page_data, req2 = get_hidden_data(req, 2) # 1就是主修课程

kklxdm = search_form_kklxdm(req, 2)

form_data = {

'filter_list[0]': lesson_name, # ok

'xqh_id': get_input_value('xqh_id', req), # ok

'jg_id': get_input_value('jg_id_1', req), # ok-------------

'zyh_id': get_input_value('zyh_id', req), # ok

'zyfx_id': get_input_value('zyfx_id', req), # ok

'njdm_id': get_input_value('njdm_id', req), # ok

'bh_id': get_input_value('bh_id', req), # ok

'xbm': get_input_value('xbm', req), # ok

'xslbdm': get_input_value('xslbdm', req), # ok

'ccdm': get_input_value('ccdm', req), # ok

'xsbj': get_input_value('xsbj', req), # ok

'xkxnm': get_input_value('xkxnm', req), # ok

'xkxqm': get_input_value('xkxqm', req), # ok

'jxbzb': get_input_value('jxbzb', req), # ok

'sfkknj': get_input_value('sfkknj', req2), # ok

'sfkkzy': get_input_value('sfkkzy', req2), # ok

'sfznkx': get_input_value('sfznkx', req2), # ok

'zdkxms': get_input_value('zdkxms', req2), # ok

'sfkxq': get_input_value('sfkxq', req2), # ok

'sfkcfx': get_input_value('sfkcfx', req2), # ok

'kkbk': get_input_value('kkbk', req2), # ok

'kkbkdj': get_input_value('kkbkdj', req2), # ok

'sfkgbcx': get_input_value('sfkgbcx', req2), # ok

'sfrxtgkcxd': get_input_value('sfrxtgkcxd', req2), # ok

'tykczgxdcs': get_input_value('tykczgxdcs', req2), # ok

'rlkz': get_input_value('rlkz', req2), # ok

'rwlx': get_input_value('rwlx', req2), # ok

'xkly': get_input_value('xkly', req2), # ok

'bklx_id': get_input_value('bklx_id', req2), # ok

'kklxdm': kklxdm[0], # ok-------------

'kspage': str(int(page_data['jspage']) + 1), # -------

'jspage': str(int(page_data['jspage']) + 10), # -------

}

header['Referer'] = req.url

request = reqs('post', this_url, param_data=param_data, form_data=form_data)

你会发现选修课程搜索会出现两个post数据,并且第二个发送的内容和返回的内容都不同,那就都post一下把,保存这些数据明天用,大同小异,这里就不讲解了,今天的任务也算完成了。最后附上代码(把昨天的修改了一下验证码不能手动输入的错误。写到凌晨两点,太困了,后面的都很潦草过了,不懂的可以在评论区或者私聊我):

GZschool.py

import re

import requests

import time

import yzm_deal

import json

username = input('帐号:')

password = input('密码:')

seting = 160

isAutoYzm = input('\n是否自动识别验证码(N/n取消): ')

enter_choose_num = '' # 进入选修课的代号

url = 'https://cas.gzhu.edu.cn/cas_server/login?service=https%3A%2F%2Fcas.gzhu.edu.cn%3A443%2Fshunt%2Findex.jsp'

header = {

'User-Agent': 'Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/9.0.084.36 Safari/536.5',

}

session = requests.session()

def reqs(action, this_url, param_data={}, form_data={}, Time=30, error_tip='网络不流畅,重试中。。。'):

# 请求

while True:

try:

if action == 'get' or action == 'GET':

return session.get(this_url, params=param_data, headers=header, timeout=Time)

elif action == 'post' or action == 'POST':

return session.post(this_url, params=param_data, data=form_data, headers=header, timeout=Time)

break

except Exception as e:

if str(e).find('timed out') > -1:

print(error_tip)

else:

print(e)

input()

continue

def captcha(): # 验证码处理

this_url = 'https://cas.gzhu.edu.cn/cas_server/captcha.jsp'

request = reqs('get', this_url)

with open('code.png', 'wb')as f:

f.write(request.content)

yzm_deal.yzm_print(seting)

if isAutoYzm != 'N' and isAutoYzm != 'n':

code = yzm_deal.yzm_deal(seting)

print('code OCR result: ' + code)

return code

else:

code = input('Please input the code: ')

return code

def login():

request = reqs('get', url) # 进入首页

this_url = 'https://cas.gzhu.edu.cn' + re.search(r'fm1" action="(.*?)"', request.text).groups()[0] # 登录按钮链接

lt = re.search(r'lt" value="(.*?)"', request.text).groups()[0] # 登录form['lt']

execution = re.search(r'execution" value="(.*?)"', request.text).groups()[0] # 登录form['execution']

form_data = {

'username': username,

'password': password,

'captcha': captcha(),

'warn': 'true',

'lt': lt,

'execution': execution,

'_eventId': 'submit',

'submit': '登录'

}

header['Referer'] = url

reqs('post', this_url, form_data)

request = reqs('get', 'http://jwxt.gzhu.edu.cn/sso/lyiotlogin')

time.sleep(0.5)

return request

def get_name(req):

this_url = 'http://jwxt.gzhu.edu.cn/jwglxt/xtgl/index_cxYhxxIndex.html'

param_data = {

'xt': 'jw',

'localeKey': 'zh_CN',

'_': str(int(time.time() * 1000)),

'gnmkdm': 'index',

'su': username

}

header['Referer'] = req.url

request = reqs('get', this_url, param_data=param_data)

name = re.search(r'media-heading">(.*?)', request.text).groups()[0]

return name

def enter_choose(req):

global enter_choose_num

global ver

gnmkdm = re.search(r"\'(.{1,8})\',\'(.{10,50})\',\'自主选课", req.text).groups()

enter_choose_num = gnmkdm[0]

this_url = 'http://jwxt.gzhu.edu.cn/jwglxt' + gnmkdm[1]

param_data = {

'gnmkdm': gnmkdm[0],

'layout': 'default',

'su': username

}

header['Referer'] = req.url

request = reqs('get', this_url, param_data=param_data)

return request

def get_input_value(id, req):

result = re.search(str(id) + '"' + '.*?value="(.*?)"', req.text).groups()[0]

return result

def get_hidden_data_form(req):

this_url = 'http://jwxt.gzhu.edu.cn/jwglxt/js/comp/jwglxt/xkgl/xsxk/zzxkYzb.js'

ver = re.search(r'ver=(.*?)"', req.text).groups()[0]

param_data = {

'ver': ver

}

header['Referer'] = req.url

request = reqs('get', this_url, param_data=param_data)

result = json.loads('{"' + re.search(r'kspage\D*\d*\D*\d*', request.text).group() + '}')

return result

def get_hidden_data(req, num):

this_url = 'http://jwxt.gzhu.edu.cn/jwglxt/xsxk/zzxkyzb_cxZzxkYzbDisplay.html'

page_data = get_hidden_data_form(req)

xkkz_id = search_form_kklxdm(req, num)[1]

form_data = {

'xkkz_id': xkkz_id,

'xszxzt': get_input_value('xszxzt', req),

'kspage': page_data['kspage'],

'jspage': page_data['jspage']

}

param_data = {

'gnmkdm': enter_choose_num,

'su': username

}

header['Referer'] = req.url

request = reqs('post', this_url, param_data=param_data, form_data=form_data)

return page_data, request

def search_form_kklxdm(req, num):

result = re.findall(r'queryCourse.*?,(.*?)\)', req.text)

if num == 1:

return eval('[' + result[0] + ']')

else:

return eval('[' + result[1] + ']')

def search(req):

this_url = 'http://jwxt.gzhu.edu.cn/jwglxt/xsxk/zzxkyzb_cxZzxkYzbPartDisplay.html'

lesson_name = input('\n请输入课程名称:') # ok------------

lesson_choose = input('\n主修课程请按"1",选修课程请按"2":')

param_data = {

'gnmkdm': enter_choose_num,

'su': username

}

if lesson_choose == '1':

page_data, req2 = get_hidden_data(req, 1) # 1就是主修课程

kklxdm = search_form_kklxdm(req, 1)

else:

page_data, req2 = get_hidden_data(req, 2) # 2就是选修课程

kklxdm = search_form_kklxdm(req, 2)

form_data = {

'filter_list[0]': lesson_name, # ok

'xqh_id': get_input_value('xqh_id', req), # ok

'jg_id': get_input_value('jg_id_1', req), # ok-------------

'zyh_id': get_input_value('zyh_id', req), # ok

'zyfx_id': get_input_value('zyfx_id', req), # ok

'njdm_id': get_input_value('njdm_id', req), # ok

'bh_id': get_input_value('bh_id', req), # ok

'xbm': get_input_value('xbm', req), # ok

'xslbdm': get_input_value('xslbdm', req), # ok

'ccdm': get_input_value('ccdm', req), # ok

'xsbj': get_input_value('xsbj', req), # ok

'xkxnm': get_input_value('xkxnm', req), # ok

'xkxqm': get_input_value('xkxqm', req), # ok

'jxbzb': get_input_value('jxbzb', req), # ok

'sfkknj': get_input_value('sfkknj', req2), # ok

'sfkkzy': get_input_value('sfkkzy', req2), # ok

'sfznkx': get_input_value('sfznkx', req2), # ok

'zdkxms': get_input_value('zdkxms', req2), # ok

'sfkxq': get_input_value('sfkxq', req2), # ok

'sfkcfx': get_input_value('sfkcfx', req2), # ok

'kkbk': get_input_value('kkbk', req2), # ok

'kkbkdj': get_input_value('kkbkdj', req2), # ok

'sfkgbcx': get_input_value('sfkgbcx', req2), # ok

'sfrxtgkcxd': get_input_value('sfrxtgkcxd', req2), # ok

'tykczgxdcs': get_input_value('tykczgxdcs', req2), # ok

'rlkz': get_input_value('rlkz', req2), # ok

'rwlx': get_input_value('rwlx', req2), # ok

'xkly': get_input_value('xkly', req2), # ok

'bklx_id': get_input_value('bklx_id', req2), # ok

'kklxdm': kklxdm[0], # ok-------------

'kspage': str(int(page_data['jspage']) + 1), # -------

'jspage': str(int(page_data['jspage']) + 10), # -------

}

header['Referer'] = req.url

request = reqs('post', this_url, param_data=param_data, form_data=form_data)

if lesson_choose != '1':

this_url2 = 'http://jwxt.gzhu.edu.cn/jwglxt/xsxk/zzxkyzb_cxJxbWithKchZzxkYzb.html'

kch_id = re.search(r'kch_id":"(\d*)', request.text).groups()[0]

cxbj = re.search(r'cxbj":"(\d*)', request.text).groups()[0]

fxbj = re.search(r'fxbj":"(\d*)', request.text).groups()[0]

form_data2 = {

'filter_list[0]': lesson_name, # ok

'xqh_id': get_input_value('xqh_id', req), # ok

'jg_id': get_input_value('jg_id_1', req), # ok

'zyh_id': get_input_value('zyh_id', req), # ok

'zyfx_id': get_input_value('zyfx_id', req), # ok

'njdm_id': get_input_value('njdm_id', req), # ok

'bh_id': get_input_value('bh_id', req), # ok

'xbm': get_input_value('xbm', req), # ok

'xslbdm': get_input_value('xslbdm', req), # ok

'ccdm': get_input_value('ccdm', req), # ok

'xsbj': get_input_value('xsbj', req), # ok

'xkxnm': get_input_value('xkxnm', req), # ok

'xkxqm': get_input_value('xkxqm', req), # ok

'sfkknj': get_input_value('sfkknj', req2), # ok

'sfkkzy': get_input_value('sfkkzy', req2), # ok

'sfznkx': get_input_value('sfznkx', req2), # ok

'zdkxms': get_input_value('zdkxms', req2), # ok

'sfkxq': get_input_value('sfkxq', req2), # ok

'sfkcfx': get_input_value('sfkcfx', req2), # ok

'kkbk': get_input_value('kkbk', req2), # ok

'kkbkdj': get_input_value('kkbkdj', req2), # ok

'rwlx': get_input_value('rwlx', req2), # ok

'xkly': get_input_value('xkly', req2), # ok

'bklx_id': get_input_value('bklx_id', req2), # ok

'rlkz': get_input_value('rlkz', req2), # ok

'kklxdm': kklxdm[0], # ok--------------

'kch_id': kch_id,

'xkkz_id': kklxdm[1],

'cxbj': cxbj,

'fxbj': fxbj

}

header['Referer'] = req.url

request = reqs('post', this_url2, param_data=param_data, form_data=form_data2)

print(request.text)

def main():

req = login()

name = get_name(req)

print('\n欢迎 ' + name + ' 同学')

req = enter_choose(req) # 进入自主选课界面

req = search(req) # 搜索课程界面

if __name__ == '__main__':

main()

yzm_deal.py:

from PIL import Image

import tesserocr # 没有安装的请注释掉并使用手动输入

def binarizing(img, seting):

# 二值化,seting为控制阀值

img = img.convert("L") # 转灰度

pixdata = img.load()

w, h = img.size

for x in range(w):

for y in range(h):

if pixdata[x, y] < seting:

pixdata[x, y] = 0

else:

pixdata[x, y] = 255

return img

def yzm_deal(seting):

img = binarizing(Image.open('code.png'), seting)

img.save('code.png', quality=100)

result = tesserocr.image_to_text(img, lang='eng')

exclude_char_list = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890'

text = ''.join([x for x in result if x in exclude_char_list])

return text

def yzm_print(seting):

# 手动输入打印验证码

img = binarizing(Image.open('code.png'), seting)

pixdata = img.load()

w, h = img.size

for y in range(h - 7):

for x in range(w):

if pixdata[x, y] == 0:

print('8', end='')

else:

print(' ', end='')

print()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值