女朋友是药学院的,做实验时需要在特定的网站上进行设备预约,由于预约人数过多,从而导致从浏览器登录不进去或者登录进去预约失败等情况,所以我用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抢票开发——设备预约助手实现的更多相关文章

  1. 春运到了,带你用python来抢票回家!

    不知不觉,一年一度的春运抢票大幕已经拉开,想快速抢到回家的车票吗?作为程序员,这些技术手段,你一定要知道. 为了让大家更快捷更便利的抢火车票,各种各样的抢票软件应需而生,这类软件大部分都是付费抢票的机 ...

  2. 用Python抢到回家的车票,so easy!

    “ 盼望着,盼望着,春节的脚步近了,然而,每年到这个时候,最难的,莫过于一张回家的火车票. ​ 据悉,今年春运期间,全国铁路发送旅客人次同比将增长 8.0%.达到 4.4 亿人次. ​ 2020 年铁 ...

  3. 12306 抢票项目霸榜 GitHub,标星即将破万

    十一将至,你买到回家的火车票了吗?如果没有,你可以试着打开 GitHub,在搜索栏键入 12306 的关键词,我相信你会发现一个新大陆.没错,这里有 1572 个抢票项目.它们大多用 Python.J ...

  4. 简单的Python 火车抢票程序

    当你想查询一下火车票信息的时候,你还在上12306官网吗?或是打开你手机里的APP?下面让我们来用Python写一个命令行版的火车票查看器, 只要在命令行敲一行命令就能获得你想要的火车票信息!如果你刚 ...

  5. Python 实现的 12306抢票脚本

    Python12306抢票脚本 本脚本使用一个类来实现所有代码,大体上分为以下几个模块及其步骤:- 初始化对象属性(在抢票前进行的属性初始化,包括初始化浏览器模拟对象,个人信息等).- 建立模拟浏览器 ...

  6. Python实例--12306的抢票功能

    基础知识学习 目标: 通过python程序实现自动登录下单功能 知识点: Selenium + 云打码 + Python 学习链接: 1. Python学习--Selenium模块 2. Python ...

  7. Python操作12306抢票脚本

    有一段时间没有使用Python了,前几天经朋友提起一篇关于用Python实现抢火车票的文章,百度了实现抢火车票的技术细节,网上却有不少资料,也不是新鲜的东西.在了解了一些技术手段,阅读了一些大神的博文 ...

  8. .net分流抢票助手

    官方网站: http://www.12306bypass.com/作者:Cheney.小风分流抢票基于.Net4.0框架开发,在Windows7之后的操作系统可直接打开.其他操作系统如打不开或者打开报 ...

  9. python写12306抢票

    #!/usr/bin/env python # -*- coding: utf-8 -*- ''' 利用splinter写的一个手动过验证及自动抢票的例子, 大家可以自己扩展或者弄错窗体.web端. ...

随机推荐

  1. 阿里云创建CentOS系统设置

    1 首先设置你购买的云盘配置,例如cpu,内存,磁盘类型.容量,网络类型等 2.阿里云可以使用浏览器进行远程shell连接 首先需要输入远程密码,第一次连接的时候会提示 一定要牢记 输入密码后进入sh ...

  2. 微信小程序官方指南手册,教你如何使用微信小程序!

    2017年1月9日,小程序如约而至.程序员们都讨论的热火朝天,但是真正使用过微信小程序的又有几个呢?下面今天我们给大家介绍下微信小程序到底应该如何使用? 首先,你的微信必须是最新版本的,微信官方是从要 ...

  3. 谈谈TCP中的TIME_WAIT

    所以,本文也来凑个热闹,来谈谈TIME_WAIT. 为什么要有TIME_WAIT? TIME_WAIT是TCP主动关闭连接一方的一个状态,TCP断开连接的时序图如下: 当主动断开连接的一方(Initi ...

  4. C,LINUX,数据结构部分

    1604期 第1期测试(面试精选:C,LINUX,数据结构部分) 本试卷从考试酷examcoo网站导出,文件格式为mht,请用WORD/WPS打开,并另存为doc/docx格式后再使用 试卷编号:24 ...

  5. [bzoj4300][绝世好题] (动规)

    Description 给定一个长度为n的数列ai,求ai的子序列bi的最长长度,满足bi&bi-1!=0(2<=i<=len). Input 输入文件共2行. 第一行包括一个整数 ...

  6. Uva548 Tree

    Tree You are to determine the value of the leaf node in a given binary tree that is the terminal nod ...

  7. poj 2823 二分法+单调队列

    #include<stdio.h> #include<string.h> #define N  1100000 int a[N]; int fmin[N],fmax[N]; i ...

  8. poj 2455

    题意:由一个点走到另一个点,中间的点可以重复到达,但边只能经过一次,问T条边不重复的路径里,最长的边的最小值. 分析:由于点是可以重用的,因此不必拆点.这道题有重边,而且重边都必须保留,因为点是可以重 ...

  9. NYOJ5 Binary String Matching

    Binary String Matching 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 Given two strings A and B, whose alp ...

  10. [poj2505]A multiplication game_博弈论

    A mutiplication game poj-2505 题目大意:给定一个数n和p,两个选手每次可以将p乘上[2,9].最先使得p大于n的选手胜利. 注释:$1\le n\le 429496729 ...