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':'0',
    'ExperimentationContent':'',
    'isSelectTimeScope':'false',
    'beginTime':'2019-05-27 8:0', #該字段是否會改變
    'endTime':'2019-05-27 8:0',
    'userId':'',
    'AppointmentStep':'15',
    '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)

 程序運行結果如下,到時間之后就會開始預約請求,請求結果將會在瀏覽器中顯示。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM