赞
踩
武汉大学体育馆场地可以从网上进行预约,包括羽毛球场,乒乓球场等。预约系统最近是晚上6点开始,可以预约未来2天内的场地。在所有场馆中,室内羽毛球场最为抢手,经常出现系统刚开放所有场地就被“秒杀”的情况。我有几天很想去打羽毛球但是是死活约不到场地,对此我很生气啊,所以就在思考能不能用python制作一个“抢场地机器人”,使其在系统开放预约时准时启动,代替人完成预约任务。
在开始之前,请确保你已经准备好:
这篇教程适用于武汉大学体育馆预约系统,链接在这。
python实现思路
正常手动预约非常简单,先登录然后查找对应时间可用的场地,点击预约即可,这里还有一步比较关键是支付,调用微信支付并完成支付还是比较麻烦的,但是如果本省在系统中有足够的余额便可以一键支付。转换成python来看就更简单了了,首先登陆,在保证账户余额足够的情况下,可以跳过查找位置的问题,直接对向预约的场地发起预约请求,使用余额支付即可。接下来就让我们试试看:
首先是登陆用户,很简单,这个登陆界面链验证码都没有,非常easy,打开浏览器的F12,切换到网络界面,勾选持续日志,输入用户名和密码,就登入了系统,在浏览器的网络界面中(Firefox和Chrome皆可),就可以看到有一个POST请求的参数就是你的用户名和密码,用这个地址就可以用python登陆咯。这是登录后的界面。
登录其实就是你把用户名密码提交过去,服务器给你返回一个Token或者Session,使用这个作为cookie的一部分后续服务器就知道你是谁了,所以使用python第一步登录然后就是获取这个Token或者Session。这个服务器使用的是session,登录并获取session的代码这样写。这里注意一点,进行post访问的时候需要一个文件头,来伪装自己的身份,否则原始程序的身份可能会不能访问哦。
- def Login(name,pass):
- url = 'http://gym.whu.edu.cn/loginAction!UserLogin'
- head = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0'}
- param = {'name':name, 'password':pass}
- session = requests.Session().post(url, headers = head, data = param)
- return(session.cookies.get_dict())
登录之后,并成功获取了Session,接下来正常操作应该是找可用场地,但是我们是直接预约嘛,其实是可以跳过找场地这个过程的,直接看看提交预约时,你给服务器发送的数据即可。在浏览器中进行一次提交,找到这个关键的post,可以看到以下几个参数
- fdId=32
- beginTime=2019-09-21+12:30:00
- endTime=2019-09-21+13:30:00
- ffId=4
- ggId=2
- usrId=990
- money=7.00
- ordTime=2019-09-19+19:30:00
- payType=2
研究了下,fdid应该是预定的场地编号,后面是起止时间,然后ffid是运动类型编号,ggid是场馆编号,usrId应该是使用cookie的用户账户,尝试登陆其他账户也是990,就不用了管了,接下来花钱的金额,后面ordtime应该就是请求发出的时间,最后支付类型,使用python把这些参数发出即可。函数这么写
- def Res(JSESSIONID, fdId):
- Time = '2019-09-21'
- url = 'http://gym.whu.edu.cn/OrderAction!bookOrder?deposit=0.00'
- head = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0',
- 'Host': 'gym.whu.edu.cn',
- 'Accept': 'application/json, text/javascript, */*; q=0.01',
- 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
- 'Accept-Encoding': 'gzip, deflate',
- 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
- 'X-Requested-With': 'XMLHttpRequest',
- 'Content-Length': '150',
- 'Connection': 'keep-alive',
- 'Referer': 'http://gym.whu.edu.cn/wechat/booking/gymHome.jsp?ggId=4',
- 'Cookie': 'iPlanetDirectoryPro=kZtrSgx3gCXpsQecF4Elfb; JSESSIONID=' + JSESSIONID}
- strtime = time.strftime('%Y-%m-%d+%H%%3A%M%%3A%S',time.localtime(time.time()))
- param = 'fdId=' + fdId + '&beginTime=' + Time +'+19%3A30%3A00&endTime=' + Time +\
- '+20%3A30%3A00&ffId=18&ggId=4&usrId=990&money=10.00&ordTime=' + strtime + '&payType=2'
- res = requests.post(url, data = param, headers = head, verify=False)
- return(res)
这儿我把头写的完善了点, 把乱起八糟的东西都加上了,还有最重要的session。仔细看代码,有些不一样
哪里不一样呢?在参数中的时间那,本来是冒号的地方我改成了%3A,参数直接写成冒号传入,报错Struts Problem Report,这个错误害的我好苦,网上并没有解决方案。最后试了许久想到是不是编码的问题,所以换了下编码方式,具体想了解Unicode和UTF-8以及ANSI的同学可以自行百度。换成这个传入参数柳暗花明又一村,终于成功了,击掌!!!!
最后,预定成功了,我得知道啊,上网查了下,我微信QQ都不如发邮件方便,这个都是网上查的,直接上代码吧。
- def send(flag, mess): #传入flag(成功与否的标志),mess(预定的位置时间)
- mail = smtplib.SMTP()
- mail.connect("smtp.qq.com") # 连接 qq 邮箱的SMTP服务
- mail.login("x1@qq.com", "xxxx") # 账号和授权码
- if flag == 1:
- print('预定成功')
- message = MIMEText(mess) # 邮件内容
- message['Subject'] = Header('羽毛球场预定成功提醒') # 邮件主题
- mail.sendmail("x1@qq.com", ["x2@qq.com"], message.as_string()) # 发送账号、接收账号和邮件信息
授权码查找方法如上所示。
好了,基本主要功能就完成了,在指定时间把程序跑起来就可以了,不需要掐好时间,我的想法是没到时间代码就沉睡,每10s判断一下到时间没,到开始预约的前一分钟,开始登陆预约操作,直到预约成功,发送邮件并跳出循环,结束程序,代码就完成了。
- if __name__ == '__main__':
- print('sleep_now', end = '') #未到时间,休眠
- while True:
- strtime = time.strftime('%H%M',time.localtime(time.time()))
- if strtime == '1759':
- print('Start Booking')
- res = Res(jsid, '36')
- trytime = 1
- while res.headers['Content-Length'] != '1':
- trytime += 1
- res = Res(jsid, '36')
- time.sleep(1)
- if trytime > 20:
- send(0, '预定失败')
- print(trytime)
- sys.exit()
- send(1, '预定成功')
- break
- else:
- time.sleep(10)
- print('.', end = '')
最后,放一个全部代码吧,方便大家使用
- import requests
- import time
- import json
- import smtplib
- from email.mime.text import MIMEText
- from email.header import Header
- import sys
-
- def Login(name,pass):
- url = 'http://gym.whu.edu.cn/loginAction!UserLogin'
- head = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0'}
- param = {'name':name, 'password':pass}
- session = requests.Session().post(url, headers = head, data = param)
- return(session.cookies.get_dict())
-
- def Res(JSESSIONID, fdId):
- Time = '2019-09-21'
- url = 'http://gym.whu.edu.cn/OrderAction!bookOrder?deposit=0.00'
- head = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0',
- 'Host': 'gym.whu.edu.cn',
- 'Accept': 'application/json, text/javascript, */*; q=0.01',
- 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
- 'Accept-Encoding': 'gzip, deflate',
- 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
- 'X-Requested-With': 'XMLHttpRequest',
- 'Content-Length': '150',
- 'Connection': 'keep-alive',
- 'Referer': 'http://gym.whu.edu.cn/wechat/booking/gymHome.jsp?ggId=4',
- 'Cookie': 'iPlanetDirectoryPro=kZtrSgx3gCXpsQecF4Elfb; JSESSIONID=' + JSESSIONID}
- strtime = time.strftime('%Y-%m-%d+%H%%3A%M%%3A%S',time.localtime(time.time()))
- param = 'fdId=' + fdId + '&beginTime=' + Time +'+19%3A30%3A00&endTime=' + Time +\
- '+20%3A30%3A00&ffId=18&ggId=4&usrId=990&money=10.00&ordTime=' + strtime + '&payType=2'
- res = requests.post(url, data = param, headers = head, verify=False)
- return(res)
-
- def Send(flag, mess): #传入flag(成功与否的标志),mess(预定的位置时间)
- mail = smtplib.SMTP()
- mail.connect("smtp.qq.com") # 连接 qq 邮箱的SMTP服务
- mail.login("x1@qq.com", "xxxx") # 账号和授权码
- if flag == 1:
- print('预定成功')
- message = MIMEText(mess) # 邮件内容
- message['Subject'] = Header('羽毛球场预定成功提醒') # 邮件主题
- mail.sendmail("x1@qq.com", ["x2@qq.com"], message.as_string()) # 发送账号、接收账号和邮件信息
-
- if __name__ == '__main__':
- print('sleep_now', end = '') #未到时间,休眠
- while True:
- strtime = time.strftime('%H%M',time.localtime(time.time()))
- if strtime == '1759':
- print('Start Booking')
- res = Res(jsid, '36')
- trytime = 1
- while res.headers['Content-Length'] != '1':
- trytime += 1
- res = Res(jsid, '36')
- time.sleep(1)
- if trytime > 20:
- Send(0, '预定失败')
- print(trytime)
- sys.exit()
- Send(1, '预定成功')
- break
- else:
- time.sleep(10)
- print('.', end = '')
-
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。