python抢票开发——设备预约助手实现
女朋友是药学院的,做实验时需要在特定的网站上进行设备预约,由于预约人数过多,从而导致从浏览器登录不进去或者登录进去预约失败等情况,所以我用python帮她写了一个抢位助手,让程序自动去进行位置预定,实测表明,程序的设备预定运行结果十分理想,可以预约到自己想要预约的时间段以及设备。下面分享我是如何编写该软件助手的。
首先,在浏览器开发者工具上查看浏览器和设备预定服务器的交互信息,找出关键的信息,如登录页的URL,登录信息提交页的URL,post提交的数据,Cookies信息等。这个过程不涉及编程操作。
在浏览器上,经过了登录,一系列的跳转和点击后,就到了设备预约提交页面,然后点击提交按钮之后,设备预约就成功了,在网络调试窗口中,发现点击提交按钮之后,浏览器向后台页面http://222.200.178.***/Appointment/Appointment 发起了POST 请求,查看POST请求参数后,发现参数信息含有预约时间,预约设备ID等信息,POST参数如下:
POST参数
SubjectId=2e5f5627-3bbf-4aae-ac2b-b5cc586f4d70
SubjectProjectId
SampleNo
SampleCount
SampleStuff
SampleSize
Target
UseNature=0
ExperimentationContent
isSelectTimeScope=false
beginTime=2019-05-26 8:0
endTime=2019-05-26 8:0
userId
AppointmentStep=15
AppointmentTimes=2019-05-27 12:30:00,2019-05-27 12:45:00
EquipmentId=17ee43c4-bb30-4e43-8e6b-b82de698e20b
EquipmentPartIds
ChangeAppointmentId
VirtualEquipmentBindId
AppointmentFeeTips=false
现在,基本可以明确进行设备预约需要向后台提交的数据以及提交的地址了。为了测试该POST请求正确,我把POST请求的内容复制为curl 字段了,然后在Linux shell下运行该curl字段,
curl "http://222.200.178.***/Appointment/Appointment" -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:67.0) Gecko/20100101 Firefox/67.0" -H "Accept: */*" -H "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" --compressed -H "Referer: http://222.200.178.58/Admin?CenterBoxUrl=/Equipment/AppointmentBoxIndex"%"3Fid"%"3D17ee43c4-bb30-4e43-8e6b-b82de698e20b"%"26time"%"3D424" -H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" -H "X-Requested-With: XMLHttpRequest" -H "Connection: keep-alive" -H "Cookie: ASP.NET_SessionId=yn2ot2upq03e2fssruvambif; .ASPXAUTH=43CAFF53FC7CC0B81B29369AAA24B3DB9BAB78E5E52FC467BE9CB3728B82AD0E0C55F5C92F077AE302C15F9C730018E4690E8705C18EF602A34BE70988E617710376CDC6C44C0472F8028F54B4EF5BF7E7B8DD72748C249578473E3E56CC1035FA86E765179B392276AC9DB0D098227F7BBFDE954136B1BB0EB39C4B0B1F3D25" --data "SubjectId=2e5f5627-3bbf-4aae-ac2b-b5cc586f4d70&SubjectProjectId=&SampleNo=&SampleCount=&SampleStuff=&SampleSize=&Target=&UseNature=0&ExperimentationContent=&isSelectTimeScope=false&beginTime=2019-05-26 8:0&endTime=2019-05-26 8:0&userId=&AppointmentStep=15&AppointmentTimes=2019-05-27 12:30:00,2019-05-27 12:45:00&EquipmentId=17ee43c4-bb30-4e43-8e6b-b82de698e20b&EquipmentPartIds=&ChangeAppointmentId=&VirtualEquipmentBindId=&AppointmentFeeTips=false"
返回的结果是提示我设备预约成功。到了这一步,可以理出一个基本的编程实现思路:构造POST请求参数,向指定的URL提交POST请求,用python实现就是import requests, requests.post(url,postdata),很简单,对不对。嗯嗯~,是不是我们的设备预约助手到这里就可以结束呢,回头再看一下curl 字段的内容,发现了下面的cookies 信息
Cookie:
ASP.NET_SessionId=yn2ot2upq03e2fssruvambif;
.ASPXAUTH=43CAFF53FC7CC0B81B29369AAA24B3DB9BAB78E5E52FC467BE9CB3728B82AD0E0C55F5C92F077AE302C15F9C730018E4690E8705C18EF602A34BE70988E617710376CDC6C44C0472F8028F54B4EF5BF7E7B8DD72748C249578473E3E56CC1035FA86E765179B392276AC9DB0D098227F7BBFDE954136B1BB0EB39C4B0B1F3D25
既然存在cookie信息,我们每次和服务器进行交互时,就得把cookie值带上,cookie有两个,一个是ASP.NET_SessionId,另一个是.ASPXAUTH。那么服务器是什么时候把这两个cookie值提交过来的呢?我还是在浏览器上做尝试。重新返回登录界面,打开调试窗口,找到cookie参数项,发现了ASP.NET_SessionId 值,但却没看到.ASPXAUTH 值,输入账号密码之后,验证通过之后,可以看cookie参数项存在.ASPXAUTH ,至此,两个cookie值可以拿到了。
现在,可以重新理一下编程的思路了:先访问登录界面url,获取ASP.NET_SessionId 值,然后向后台登录链接发送POST请求,验证成功之后就可以获取到.ASPXAUTH cookie值,接着就是构造POST请求参数,向指定的预约URL提交POST请求,至此,整个预约助手的工作流程就明朗了。
下面是源代码:
#!/bin/bash/python3
#coding:utf-8
#实验设备抢位助手,开发by linjunji in SYSU 2019-05-27
import requests
from datetime import datetime,timedelta
import hashlib
import sys
import time
import configparser
import re
import base64
import logging
import webbrowser logging.basicConfig(level=logging.INFO,format='%(asctime)s: %(message)s') #定义登录提交URL以及预约请求URL
login_url="http://222.200.178.***/Account/Login" #登录界面url
vaild_url="http://222.200.178.***/Account/LoginSubmit" #账号密码提交验证URL
appointment_url="http://222.200.178.***/Appointment/Appointment" #预约请求提交页面 #定义头部信息
user_agent="Mozilla/5.0 (Windows NT 10.0; WOW64; rv:67.0) Gecko/20100101 Firefox/67.0"
referer="http://222.200.178.***/Admin?CenterBoxUrl=/Equipment/AppointmentBoxIndex%3Fid%3D17ee43c4-bb30-4e43-8e6b-b82de698e20b%26time%3D424"
Content_Type="application/x-www-form-urlencoded"
header={'User-Agent':user_agent,'Referer':referer,'Content-Type':Content_Type} #密码MD5计算
def get_password_md5(password):
password_bin=password.encode("utf-8")
m=hashlib.md5()
m.update(password_bin)
return m.hexdigest() #用户名base64编码
def get_base64_loginname(name):
name_b = base64.b64encode(name.encode("utf-8"))
return name_b.decode("utf-8") postdata={
'SubjectId':'2e5f5627-3bbf-4aae-ac2b-b5cc586f4d70',
'SubjectProjectId':'',
'SampleNo':'',
'SampleCount':'',
'SampleStuff':'',
'SampleSize':'',
'Target':'',
'UseNature':'',
'ExperimentationContent':'',
'isSelectTimeScope':'false',
'beginTime':'2019-05-27 8:0', #该字段是否会改变
'endTime':'2019-05-27 8:0',
'userId':'',
'AppointmentStep':'',
'AppointmentTimes':'2019-05-28 21:30:00,2019-05-28 21:45:00', #请求时间
'EquipmentId':'17ee43c4-bb30-4e43-8e6b-b82de698e20b', #设备ID号
'EquipmentPartIds':'',
'ChangeAppointmentId':'',
'VirtualEquipmentBindId':'',
'AppointmentFeeTips':'false'
}
#设备ID和名称对应表
device_msg={
"819a7b77-dc03-40f8-b1ef-1824ea8e4683":"400M核磁共振谱仪1",
"17ee43c4-bb30-4e43-8e6b-b82de698e20b":"400M核磁共振谱仪2 (AvanceIII)",
"6a7f349d-6295-4a53-817d-413f35be07bb":"500M超导核磁共振波谱仪-3"
}
pattern_title=re.compile('<div class="a_center f_bold">(.+)</div>') #匹配标题 ['您的预约已提交,请在预约时间前24小时登录确认!您当前的预约时间如下:']
pattern_head=re.compile('<th>(.+?)</th>') #匹配行数 ['开始时间', '结束时间', '时长']
pattern_time=re.compile('<td>([^//td<>]+?)</td>') #['2019年05月28 21时30分', '2019年05月28 22时00分', '0.5', '</td><td>', '共:0.5'] if __name__=="__main__":
#读取配置文件,从配置文件读取登录名,密码,预订时间,设备信息
cf=configparser.ConfigParser() #读取配置文件
try:
cf.read('config.ini')
user_name = cf.get('user', 'name')
user_password = cf.get('user','password')
time1 = cf.get('time1','time')
time2 = cf.get('time2', 'time')
time3 = cf.get('time3', 'time')
time4 = cf.get('time4', 'time')
device_id=cf.get('device','device_id')
except Exception as e:
logging.info('【respone】配置文件读取异常,请检查!,程序两秒钟后退出')
logging.info(e)
time.sleep(2)
sys.exit() logging.info("【respone】成功加载配置文件")
logging.info("【respone】{},欢迎您进入自动预订系统".format(user_name))
nextday=(datetime.now()+timedelta(days=1)).strftime('%Y-%m-%d')
booking_time=[time1,time2,time3,time4]
time_str=[' '.join([nextday,t]) for t in booking_time if len(t)>0]
booking_time_str=','.join(time_str) begin_time="{} 8:0".format(nextday)
end_time=begin_time #定义post提交数据
postdata["beginTime"] = begin_time
postdata['endTime'] = end_time
postdata['AppointmentTimes'] = booking_time_str
postdata['EquipmentId'] = device_id logging.info("【respone】你将要预约的时间是:{}".format(booking_time_str))
logging.info("【respone】你将要预订的设备是:{}".format(device_msg[device_id])) s = requests.Session() # session会话会自动把cookie带进去
# post提交登录信息
data = {"LoginName": get_base64_loginname(user_name), 'LoginPassword': get_password_md5(user_password),'date': ''}
r = s.post(vaild_url, headers=header, data=data, allow_redirects=True) # 打印出cookies信息
for cookies in r.cookies.keys():
logging.debug(cookies+':'+r.cookies.get(cookies))
r.encoding = "utf-8"
logging.debug(r.text) if (r.text.find("true") > 0):
logging.info("【respone】你已经成功登录设备预约系统...正在等待系统开放预约操作 ")
else:
logging.info("【respone】登录失败,请重新运行程序尝试,按任意字符退出")
sys.exit()
logging.info("【respone】提醒:程序将于21点59分55秒进行设备预订,请勿关闭本程序") while(True):
now = datetime.now()
hour = now.hour # 小时
minutes = now.minute # 分
second = now.second # 秒
if hour == 21 and minutes == 59 and second > 45:
logging.info("【respone】10s后开始进行设备预定")
for i in range(10):
time.sleep(1)
logging.info("【respone】{}s...".format(10 - i))
break logging.info("【respone】开始进行设备预约")
try:
r=s.post(appointment_url,data=postdata,headers=header,timeout=10)
r.encoding='utf-8'
rst=r.text
filename="booking_result.html"
f=open(filename,'w',encoding="utf-8")
f.write("<head>")
f.write("<meta charset='UTF-8'>")
f.write("<title>预订结果如下</title>")
f.write("</head>")
f.write(r.text)
f.close()
logging.info("【respone】预订结果在浏览器在浏览器查看")
webbrowser.open(filename) except Exception as e:
logging.info("【respone】本次预约可能失败,请用网页登进系统查看")
logging.info(e)
程序运行结果如下,到时间之后就会开始预约请求,请求结果将会在浏览器中显示。
python抢票开发——设备预约助手实现的更多相关文章
- 春运到了,带你用python来抢票回家!
不知不觉,一年一度的春运抢票大幕已经拉开,想快速抢到回家的车票吗?作为程序员,这些技术手段,你一定要知道. 为了让大家更快捷更便利的抢火车票,各种各样的抢票软件应需而生,这类软件大部分都是付费抢票的机 ...
- 用Python抢到回家的车票,so easy!
“ 盼望着,盼望着,春节的脚步近了,然而,每年到这个时候,最难的,莫过于一张回家的火车票. 据悉,今年春运期间,全国铁路发送旅客人次同比将增长 8.0%.达到 4.4 亿人次. 2020 年铁 ...
- 12306 抢票项目霸榜 GitHub,标星即将破万
十一将至,你买到回家的火车票了吗?如果没有,你可以试着打开 GitHub,在搜索栏键入 12306 的关键词,我相信你会发现一个新大陆.没错,这里有 1572 个抢票项目.它们大多用 Python.J ...
- 简单的Python 火车抢票程序
当你想查询一下火车票信息的时候,你还在上12306官网吗?或是打开你手机里的APP?下面让我们来用Python写一个命令行版的火车票查看器, 只要在命令行敲一行命令就能获得你想要的火车票信息!如果你刚 ...
- Python 实现的 12306抢票脚本
Python12306抢票脚本 本脚本使用一个类来实现所有代码,大体上分为以下几个模块及其步骤:- 初始化对象属性(在抢票前进行的属性初始化,包括初始化浏览器模拟对象,个人信息等).- 建立模拟浏览器 ...
- Python实例--12306的抢票功能
基础知识学习 目标: 通过python程序实现自动登录下单功能 知识点: Selenium + 云打码 + Python 学习链接: 1. Python学习--Selenium模块 2. Python ...
- Python操作12306抢票脚本
有一段时间没有使用Python了,前几天经朋友提起一篇关于用Python实现抢火车票的文章,百度了实现抢火车票的技术细节,网上却有不少资料,也不是新鲜的东西.在了解了一些技术手段,阅读了一些大神的博文 ...
- .net分流抢票助手
官方网站: http://www.12306bypass.com/作者:Cheney.小风分流抢票基于.Net4.0框架开发,在Windows7之后的操作系统可直接打开.其他操作系统如打不开或者打开报 ...
- python写12306抢票
#!/usr/bin/env python # -*- coding: utf-8 -*- ''' 利用splinter写的一个手动过验证及自动抢票的例子, 大家可以自己扩展或者弄错窗体.web端. ...
随机推荐
- (六)python3 字符串常用方法
字符串截取 >>>s = 'hello' >>>s[0:3] 'he' >>>s[:] #截取全部字符 'hello' 消除空格及特殊符号 ...
- Python生成随机不重复姓名昵称
姓采用百家姓,名字从常用名字高频字选取两个汉字,再和当前时间戳组合,估计应该是不会重复了,代码如下: # -*- coding:utf-8 -*- import random import time ...
- 突击战 (UVA 11729)
题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=28436 思路:任务从开始时就不停执行,与其他任务毫无关联,当然是执 ...
- PAT 1142 Maximal Clique
A clique is a subset of vertices of an undirected graph such that every two distinct vertices in the ...
- java List 数组删除元素
在 java 中,ArrayList 是一个很常用的类,在编程中经常要对 ArrayList 进行增.删.改.查操作.之前在学校时一直认为删除操作是最简单的,现在才越发觉得自己愚蠢.只需要设置好预期条 ...
- MongoDB:最简单的增删改查(Oops,可能太简单了)
热身运动: 1. 启动MongoDB shell => mongo.exe or ./mongo(先确保有一个mongod的实例): 2. 切换到一个用于练手的namespace => u ...
- ci get_instance()
你随便下个CI框架的源码都会看到很多的get_instance() 函数,这个函数是用来获取CI 的全局超级对象,CI 是单例模式的框架,所有全局有一个超级对象.因为只有一个实例,所以无论这个函数使用 ...
- 如何基于udp实现tcp协议栈
http://bbs.csdn.net/topics/280046868 使用套接字完成,按照tcp的方式在一个套接字里维持一个状态机. //定义枚举: enmu state{ CLOSED,//没有 ...
- 【Android实战】记录自学自己定义GifView过程,能同一时候支持gif和其它图片!【有用篇】
之前写了一篇博客.<[Android实战]记录自学自己定义GifView过程,具体解释属性那些事! [学习篇]> 关于自己定义GifView的,具体解说了学习过程及遇到的一些类的解释,然后 ...
- Linux C 网络编程——多线程的聊天室实现(server端)
server端的主要功能: 实现多用户群体聊天功能(此程序最多设定为10人.可进行更改),每一个人所发送的消息其它用户均能够收到.用户能够任意的增加或退出(推出以字符串"bye"实 ...