又到瘋狂搶票的高峰期仙辟,用python寫(xiě)一個(gè)簡(jiǎn)單的12306搶票軟件

引言

每逢過(guò)年就到了12306搶票高峰期,自己總想研究一下12306購(gòu)票的流程未檩,雖然網(wǎng)上已經(jīng)很多資料冤狡,但是總比不過(guò)自己的親身體會(huì)项棠,于是便琢磨著寫(xiě)一個(gè)搶票軟件香追,本人比較熟悉python透典,所以軟件是用python寫(xiě)的峭咒。

使用工具和庫(kù)

開(kāi)發(fā)環(huán)境是python3.6.2

開(kāi)發(fā)工具是pycharm

輔助工具fiddler(神器)

使用到的重要庫(kù):

界面(tkinter)

http請(qǐng)求(requests庫(kù))

打包(pyinstaller庫(kù))

思考過(guò)程

其實(shí)本人職業(yè)并不是開(kāi)發(fā)人員讹语,任職是測(cè)試顽决,但是喜歡平時(shí)用python寫(xiě)點(diǎn)小東西导匣,所以開(kāi)發(fā)大大們莫見(jiàn)笑贡定。不廢話,說(shuō)說(shuō)我才開(kāi)始做的思考過(guò)程渠牲。

1.首先代碼需要涉及前端和后臺(tái)兩個(gè)部分签杈,前端我查了PyQt和Tkinter答姥,覺(jué)得我這小東西沒(méi)必要用PyQt鹦付,畫(huà)個(gè)簡(jiǎn)單的前端即可敲长,所以選擇使用Tkinter

2.后臺(tái)代碼就是模擬12306訂票流程互捌,所以選擇requests庫(kù)做http請(qǐng)求

3.12306訂票流程怎么去分解秕噪?fiddler神器幫了大忙腌巾,我就去12306官網(wǎng)正常登錄購(gòu)票澈蝙,把整個(gè)流程的包全部抓到灯荧,然后分析請(qǐng)求數(shù)據(jù)和返回?cái)?shù)據(jù)逗载,后臺(tái)代碼就比較容易寫(xiě)了

4.根據(jù)后臺(tái)代碼的邏輯和返回厉斟,編寫(xiě)前端的用戶提示和跳轉(zhuǎn)

模擬12306購(gòu)票流程

第一步登錄:

在你登錄12306網(wǎng)站的時(shí)候擦秽,網(wǎng)頁(yè)會(huì)get一個(gè)驗(yàn)證碼圖片,這個(gè)步驟封裝方法如下:

def get_img(self):

url="https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand&{}".format(random.random())

response=self.session.get(url=url,headers=self.headers,cookies=Func12306.cookies, verify=False)

path = os.path.abspath('..')

with open(path+"\img.jpg",'wb') as f:

f.write(response.content)

值得注意的是在抓包的時(shí)候發(fā)現(xiàn)請(qǐng)求里有個(gè)隨機(jī)數(shù)越败,這里get請(qǐng)求需要帶上這個(gè)隨機(jī)數(shù)眉尸,所以使用了

random()

headers可以在初始化的時(shí)候?qū)懞?/p>

self.headers = {

'Accept-Encoding': 'gzip, deflate, br',

'Accept-Language': 'zh-CN,zh;q=0.8',

'X-Requested-With': 'XMLHttpRequest',

'Origin': 'https://kyfw.12306.cn',

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.4355.400 QQBrowser/9.7.12672.400',

'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',

'Accept': 'application/json, text/javascript, */*; q=0.01',

}

cookies會(huì)在你登錄的時(shí)候自動(dòng)保存在session里面 驗(yàn)證碼圖片可以保存在本地文件夾,然后給前端調(diào)用

根據(jù)fiddler抓到包的順序來(lái)看袱蜡,12306是先驗(yàn)證驗(yàn)證碼坪蚁,再驗(yàn)證帳號(hào)和密碼敏晤,所以我們第一步是發(fā)送驗(yàn)證碼信息給12306

驗(yàn)證碼是由8個(gè)圖片組成缅茉,12306服務(wù)器是校驗(yàn)的用戶點(diǎn)擊坐標(biāo)來(lái)識(shí)別的蔬墩,這里我們直接固定給出每個(gè)圖片的中心坐標(biāo)拇颅,簡(jiǎn)化了驗(yàn)證邏輯

def verify(self, clickList):

url = 'https://kyfw.12306.cn/passport/captcha/captcha-check'

code = ['35,35', '105,35', '175,35', '245,35', '35,105', '105,105', '175,105', '245,105']

verifyList = []

for a in clickList:

verifyList.append(code[int(a)])

codeList = ','.join(verifyList)

data = {

'answer': codeList,

'login_site': 'E',

'rand': 'sjrand',

'_json_att':"",

}

response = self.session.post(url=url, data=data, headers=self.headers, cookies=Func12306.cookies,verify=False)

try:

dic = loads(response.content)

except:

return "NetWorkError"

resultCode = dic['result_code']

resultMsg = dic['result_message']

self.verifyInfo = resultMsg

if str(resultCode) == "4":

return "verifySuccessful"

else:

return False

這是封裝好的驗(yàn)證碼驗(yàn)證邏輯

接下來(lái)就是要驗(yàn)證帳號(hào)和密碼韵洋,根據(jù)fiddler抓包來(lái)看麻献,驗(yàn)證一共發(fā)了三個(gè)請(qǐng)求,獲得了一些需要后續(xù)驗(yàn)證在線的key旅赢,下面給出代碼

def login(self, account, password):

url = 'https://kyfw.12306.cn/passport/web/login'

data = {

'username': account,

'password': password,

'appid': 'otn',

'_json_att': "",

}

response = self.session.post(url=url, data=data, headers=self.headers, cookies=Func12306.cookies,verify=False)

try:

dic = loads(response.content)

except:

return "NetWorkError"

resultCode = dic['result_code']

resultMsg = dic['result_message']

self.loginInfo = resultMsg

if resultCode == 0:

print('登陸成功')

else:

return "loginFail"

if 'uamtk' in dic.keys():

Func12306.uamtk = dic['uamtk']

url2 = 'https://kyfw.12306.cn/passport/web/auth/uamtk'

data2 = {

"appid": "otn",

'_json_att':""

}

# Func12306.cookies['uamtk'] = Func12306.uamtk

response2 = self.session.post(url=url2, data=data2, headers=self.headers, cookies=Func12306.cookies,verify=False)

try:

dic2 = loads(response2.content)

except:

return "NetWorkError"

resultCode2 = dic['result_code']

resultMsg2 = dic['result_message']

self.loginInfo = resultMsg2

if resultCode2 == 0:

print('驗(yàn)證通過(guò)')

else:

return "authFail"

if 'newapptk' in dic2.keys():

Func12306.tk = dic2["newapptk"]

# Func12306.cookies.pop('uamtk')

# Func12306.cookies['tk'] = Func12306.tk

url3 = 'https://kyfw.12306.cn/otn/uamauthclient'

data3 = {"tk": Func12306.tk,

'_json_att': "",

}

response3 = self.session.post(url=url3, data=data3, headers=self.headers, cookies=Func12306.cookies,verify=False)

try:

dic3 = loads(response3.content)

except:

return "NetWorkError"

resultCode3 = dic3['result_code']

resultMsg3 = dic3['result_message']

self.loginInfo = resultMsg3

if resultCode3 == 0:

return "LoginSuccessful"

else:

return False

登錄成功后短纵,我們需要前端跳轉(zhuǎn)到我們自己設(shè)計(jì)的搶票UI上香到,UI的設(shè)計(jì)比較簡(jiǎn)陋悠就,我給個(gè)圖

查詢用戶聯(lián)系人信息

這里和12306邏輯不一樣的是梗脾,我們是搶票軟件炸茧,聯(lián)系是提前選擇好的梭冠,而12306是在購(gòu)票的時(shí)候填寫(xiě)的控漠,所以我們要先提前獲取到聯(lián)系人然后插入到我們的前端里面润脸,下面給出聯(lián)系人的獲取

def get_passenger_info(self):

url = 'https://kyfw.12306.cn/otn/confirmPassenger/getPassengerDTOs'

data = {

"_json_att": "",

"REPEAT_SUBMIT_TOKEN": Func12306.reSubmitTk

}

response = self.session.post(url=url, data=data, headers=self.headers, cookies=Func12306.cookies,verify=False)

try:

dic = loads(response.content)

except:

return "NetWorkError"

if dic['messages'] != []:

if dic['messages'][0] == '系統(tǒng)忙毙驯,請(qǐng)稍后重試':

return 'systembusy'

Func12306.passengerAllInfoList = dic['data']['normal_passengers']

for a in Func12306.passengerAllInfoList:

Func12306.passengerNameList.append(a['passenger_name'])

Func12306.passengerIdList.append(a['passenger_id_no'])

Func12306.passengerPhoneList.append(a['mobile_no'])

return Func12306.passengerNameList

查詢車(chē)次

聯(lián)系人獲取完畢,座位類(lèi)型是自己研究12306后固定寫(xiě)上去的

這個(gè)時(shí)候下一步就是查詢車(chē)次

這里給出代碼

def search_ticket(self, startStation, endStation, startDate):

try:

Func12306.cookies['_jc_save_fromDate'] = startDate

Func12306.cookies['_jc_save_fromStation'] = (parse.quote(startStation.encode('unicode_escape').decode('latin-1') + ',' + self.stationCodeDict[startStation]).replace('\','%')).upper().replace('%5CU', '%u')

Func12306.cookies['_jc_save_toDate'] = startDate

Func12306.cookies['_jc_save_toStation'] = (parse.quote(endStation.encode('unicode_escape').decode('latin-1') + ',' + self.stationCodeDict[endStation]).replace('\','%')).upper().replace('%5CU', '%u')

Func12306.cookies['_jc_save_wfdc_flag'] = "dc"

except:

return "wrongtype"

try:

url1 = 'https://kyfw.12306.cn/otn/leftTicket/log?leftTicketDTO.train_date={}&leftTicketDTO.from_station={}&leftTicketDTO.to_station={}&purpose_codes=ADULT'.format(startDate, self.stationCodeDict[startStation], self.stationCodeDict[endStation])

except:

return "wrongtype"

response1 = self.session.get(url=url1, headers=self.headers, cookies=Func12306.cookies, verify=False)

try:

dic1 = loads(response1.content)

except:

return "NetWorkError"

if dic1['status']:

print("OK")

else:

return "searchFail"

try:

url2 = 'https://kyfw.12306.cn/otn/{}?leftTicketDTO.train_date={}&leftTicketDTO.from_station={}&leftTicketDTO.to_station={}&purpose_codes=ADULT'.format(Func12306.query, startDate, self.stationCodeDict[startStation], self.stationCodeDict[endStation])

except:

return "wrongtype"

response2 = self.session.get(url=url2, headers=self.headers, cookies=Func12306.cookies, verify=False)

try:

dic2 = loads(response2.content)

except:

return "NetWorkError"

if dic2 == "":

return "NetWorkError"

if dic2['status'] is False:

if 'c_url' in dic2.keys():

Func12306.query = dic2['c_url']

return "statusError"

return "statusError"

# elif dic2["messages"] != []:

# # if dic["messages"][0] == u"選擇的查詢?nèi)掌诓辉陬A(yù)售日期范圍內(nèi)":

# return "search_error002"

else:

print("查詢車(chē)成功")

Func12306.trainInfoStartTimeList, Func12306.trainInfoEndTimeList, Func12306.trainInfoSecretStrList, Func12306.trainInfoNameList, Func12306.trainInfoLocationList, Func12306.trainInfoNoList = [], [], [], [], [], []

Func12306.dw, Func12306.swz, Func12306.ydz, Func12306.edz, Func12306.yz, Func12306.yw, Func12306.wz, Func12306.rw, Func12306.gjrw, Func12306.tdz, Func12306.rz = [], [], [], [], [], [], [], [], [], [], []

Func12306.seatTypeList = (Func12306.edz, Func12306.ydz, Func12306.yz, Func12306.rz, Func12306.yw, Func12306.rw, Func12306.dw, Func12306.wz, Func12306.swz, Func12306.tdz, Func12306.gjrw)

for a in dic2['data']['result']:

Func12306.trainInfoSecretStrList.append(a.split("|")[0])

Func12306.trainInfoNoList.append(a.split("|")[2])

Func12306.trainInfoNameList.append(a.split("|")[3])

Func12306.trainInfoStartTimeList.append(a.split("|")[8])

Func12306.trainInfoEndTimeList.append(a.split("|")[9])

Func12306.trainInfoLocationList.append(a.split("|")[15])

Func12306.dw.append(a.split("|")[33])

Func12306.swz.append(a.split("|")[32])

Func12306.ydz.append(a.split("|")[31])

Func12306.edz.append(a.split("|")[30])

Func12306.yz.append(a.split("|")[29])

Func12306.yw.append(a.split("|")[28])

Func12306.wz.append(a.split("|")[26])

Func12306.tdz.append(a.split("|")[25])

Func12306.rz.append(a.split("|")[24])

Func12306.rw.append(a.split("|")[23])

Func12306.gjrw.append(a.split("|")[21])

Func12306.seatTypeList = (

Func12306.edz, Func12306.ydz, Func12306.yz, Func12306.rz, Func12306.yw, Func12306.rw, Func12306.dw,

Func12306.wz, Func12306.swz, Func12306.tdz, Func12306.gjrw)

return Func12306.trainInfoNameList

這里值得注意的是查詢出來(lái)的結(jié)果是用“|分隔的很多信息秦爆,需要自己研究每個(gè)位置是什么信息等限,可以對(duì)照12306頁(yè)面研究,然后把獲取的信息返回給前端調(diào)用

還有重要一點(diǎn)要注意就是12306的url不是固定的锰霜,它會(huì)帶一個(gè)隨機(jī)的大字字母在url里癣缅,我們可以先隨便寫(xiě)一個(gè)友存,然后從返回值里獲取到這個(gè)大寫(xiě)字母

搶票邏輯

這個(gè)時(shí)候我們就可以讓用戶選擇車(chē)次和聯(lián)系人以及座位類(lèi)型爬立,然后就可以進(jìn)入搶票邏輯

搶票需要發(fā)送很多請(qǐng)求

首先我們要知道我們要買(mǎi)的票到底有還是沒(méi)有

def check_ticket(self, startStation, endStation, startDate, seatType, passengersList, trainName):

searchResult = self.search_ticket(startStation, endStation, startDate)

# print(searchResult)

# print(Func12306.edz)

if searchResult == "wrongtype":

return "wrongtype"

if searchResult == "NetWorkError":

return "NetWorkError"

if searchResult == "searchFail":

return "searchFail"

if searchResult == "statusError":

return "statusError"

if searchResult == "search_error002":

return "search_error002"

for a in trainName:

try:

trainIndex = Func12306.trainInfoNameList.index(a)

except:

return "listNeedRefresh"

for b in seatType:

# print(trainIndex)

# print(b)

# print(Func12306.seatTypeList)

# print(Func12306.seatTypeList[b])

if Func12306.trainInfoSecretStrList[trainIndex] == 'null':

print('沒(méi)票了')

break

elif Func12306.seatTypeList[b][trainIndex] == u"無(wú)" or Func12306.seatTypeList[b][trainIndex] == "" :

print("沒(méi)票了")

continue

elif Func12306.seatTypeList[b][trainIndex] == "*":

print("還沒(méi)開(kāi)始售票")

continue

elif Func12306.seatTypeList[b][trainIndex] != u"有" and len(passengersList) > int(Func12306.seatTypeList[b][trainIndex]):

print("票沒(méi)人多")

continue

else:

print("查詢到有票")

Func12306.trainIndexOfBuy = trainIndex

Func12306.seatIndexOfBuy = b

return Func12306.seatTypeList[b][trainIndex]

這里面還涉及多人購(gòu)買(mǎi)的時(shí)候,票不夠人多的情況吟策,我這邊處理是沒(méi)足夠的票檩坚,大家就都不買(mǎi)匾委,要買(mǎi)一起買(mǎi) 赂乐。如果票足夠了挨措,我們就開(kāi)始進(jìn)入購(gòu)票環(huán)節(jié)

首先需要驗(yàn)證用戶信息

def check_user(self):

url = 'https://kyfw.12306.cn/otn/login/checkUser'

data = {"_json_att": ""}

# self.headers["Cache-Control"] = "no-cache"

# self.headers["If-Modified-Since"] = "0"

response = self.session.post(url=url, data=data, headers=self.headers, cookies=Func12306.cookies,verify=False)

try:

dic = loads(response.content)

except:

return "NetWorkError"

if dic['data']['flag']:

print("用戶在線驗(yàn)證成功")

return True

else:

print('檢查到用戶不在線崩溪,請(qǐng)重新登陸')

return False

驗(yàn)證完之后需要開(kāi)始提交訂單

def submit_order(self, startStation, endStation, startDate):

url = 'https://kyfw.12306.cn/otn/leftTicket/submitOrderRequest'

data = {"secretStr": parse.unquote(Func12306.trainInfoSecretStrList[Func12306.trainIndexOfBuy]),

"train_date": startDate,

"back_train_date": startDate,

"tour_flag": "dc",

"purpose_codes": "ADULT",

"query_from_station_name": startStation,

"query_to_station_name": endStation,

"undefined": ""

}

response=self.session.post(url=url, data=data, headers=self.headers,cookies=Func12306.cookies, verify=False)

try:

dic = loads(response.content)

except:

return "NetWorkError"

if dic['status']:

print('提交訂單成功')

return True

elif dic['messages'] != []:

if dic['messages'][0] == "車(chē)票信息已過(guò)期觉既,請(qǐng)重新查詢最新車(chē)票信息":

print('車(chē)票信息已過(guò)期瞪讼,請(qǐng)重新查詢最新車(chē)票信息')

return "ticketInfoOutData"

else:

print("提交失敗")

return False

提交完然后開(kāi)始確認(rèn)聯(lián)系人信息

def confirm_passenger(self):

url = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'

data = {"_json_att": ''}

response=self.session.post(url=url,data=data,headers=self.headers, cookies=Func12306.cookies,verify=False)

try:

Func12306.reSubmitTk = re.findall(u'globalRepeatSubmitToken = '(S+?)'',response.text)[0]

Func12306.keyIsChange = re.findall(u'key_check_isChange':'(S+?)'',response.text)[0]

Func12306.leftTicketStr = re.findall(u'leftTicketStr':'(S+?)'',response.text)[0]

except:

print("獲取KEY失敗")

return 'NetWorkError'

def get_passenger_info(self):

url = 'https://kyfw.12306.cn/otn/confirmPassenger/getPassengerDTOs'

data = {

"_json_att": "",

"REPEAT_SUBMIT_TOKEN": Func12306.reSubmitTk

}

response = self.session.post(url=url, data=data, headers=self.headers, cookies=Func12306.cookies,verify=False)

try:

dic = loads(response.content)

except:

return "NetWorkError"

if dic['messages'] != []:

if dic['messages'][0] == '系統(tǒng)忙,請(qǐng)稍后重試':

return 'systembusy'

Func12306.passengerAllInfoList = dic['data']['normal_passengers']

for a in Func12306.passengerAllInfoList:

Func12306.passengerNameList.append(a['passenger_name'])

Func12306.passengerIdList.append(a['passenger_id_no'])

Func12306.passengerPhoneList.append(a['mobile_no'])

return Func12306.passengerNameList

確認(rèn)好聯(lián)系人之后背亥,需要開(kāi)始確認(rèn)訂單

def check_order(self, passengersList):

url = 'https://kyfw.12306.cn/otn/confirmPassenger/checkOrderInfo'

passengerTicketStr = ""

oldPassengerStr = ""

for a in passengersList:

passengerTicketStr += Func12306.seatCodeList[Func12306.seatIndexOfBuy] + ",0,1,{},1,{},{},N_".format(Func12306.passengerNameList[a], Func12306.passengerIdList[a], Func12306.passengerPhoneList[a])

oldPassengerStr += "{},1,{},1_".format(Func12306.passengerNameList[a], Func12306.passengerIdList[a])

data = {

"cancel_flag": "2",

"bed_level_order_num": "000000000000000000000000000000",

"passengerTicketStr": passengerTicketStr,

"oldPassengerStr": oldPassengerStr,

"tour_flag": "dc",

"randCode": "",

"whatsSelect": "1",

"_json_att": "",

"REPEAT_SUBMIT_TOKEN": Func12306.reSubmitTk

}

response = self.session.post(url=url, data=data, headers=self.headers,cookies=Func12306.cookies, verify=False)

try:

dic = loads(response.content)

except:

return "NetWorkError"

if dic['data']['submitStatus'] is True:

if dic['data']['ifShowPassCode'] == 'N':

return True

if dic['data']['ifShowPassCode'] == 'Y':

return "Need Random Code"

else:

print("checkOrderFail")

return False

這里有幾點(diǎn)需要注意:

1.在這個(gè)過(guò)程之前,12306會(huì)get一張新驗(yàn)證碼圖片盾戴,在購(gòu)票緊張的時(shí)候會(huì)在購(gòu)票時(shí)候彈出給你填尖啡,如果購(gòu)票不緊張就不會(huì)有但是我們要get到這張圖

2.判斷要不要填這個(gè)驗(yàn)證的key在上面代碼里’ifShowPassCode’ == ‘Y’就是要填剩膘,我們要做判斷

這里給出新驗(yàn)證碼的獲取代碼

def get_buy_image(self):

url='https://kyfw.12306.cn/otn/passcodeNew/getPassCodeNew?module=passenger&rand=randp&{}'.format(random.random())

response=self.session.get(url=url,headers=self.headers,cookies=Func12306.cookies, verify=False)

path = os.path.abspath('..')

with open(path + "\img.jpg", 'wb') as f:

f.write(response.content)

確認(rèn)訂單成功之后畏梆,我們就要開(kāi)始進(jìn)入購(gòu)票隊(duì)列

def get_queue_count(self, startStation, endStation, startDate, seatType):

url = 'https://kyfw.12306.cn/otn/confirmPassenger/getQueueCount'

thatdaydata = datetime.datetime.strptime(startDate, "%Y-%m-%d")

train_date = "{} {} {} {} 00:00:00 GMT+0800 (中國(guó)標(biāo)準(zhǔn)時(shí)間)".format(thatdaydata.strftime('%a'),

thatdaydata.strftime('%b'), startDate.split('-')[2],

startDate.split('-')[0])

data = {

"train_date": train_date,

"train_no": Func12306.trainInfoNoList[Func12306.trainIndexOfBuy],

"stationTrainCode": Func12306.trainInfoNameList[Func12306.trainIndexOfBuy],

"seatType": Func12306.seatCodeList[Func12306.seatIndexOfBuy],

"fromStationTelecode": self.stationCodeDict[startStation],

"toStationTelecode": self.stationCodeDict[endStation],

"leftTicket": Func12306.leftTicketStr,

"purpose_codes": "00",

"train_location": Func12306.trainInfoLocationList[Func12306.trainIndexOfBuy],

"_json_att": "",

"REPEAT_SUBMIT_TOKEN": Func12306.reSubmitTk

}

response=self.session.post(url=url,data=data,headers=self.headers, cookies=Func12306.cookies, verify=False)

try:

dic = loads(response.content)

except:

return "NetWorkError"

if dic['status']:

print("進(jìn)入隊(duì)列成功")

return True

else:

print("進(jìn)入隊(duì)列失敗")

return False

然后確認(rèn)單人隊(duì)列

def confirm_single_for_queue(self, seatType, passengersList, clickList = None):

url = 'https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue'

passengerTicketStr = ""

oldPassengerStr = ""

for a in passengersList:

passengerTicketStr += Func12306.seatCodeList[Func12306.seatIndexOfBuy] + ",0,1,{},1,{},{},N_".format(Func12306.passengerNameList[a], Func12306.passengerIdList[a], Func12306.passengerPhoneList[a])

oldPassengerStr += "{},1,{},1_".format(Func12306.passengerNameList[a], Func12306.passengerIdList[a])

if clickList is not None:

code = ['35,35', '105,35', '175,35', '245,35', '35,105', '105,105', '175,105', '245,105']

verifyList = []

for a in clickList:

verifyList.append(code[int(a)])

codeList = ','.join(verifyList)

print(codeList)

else:

codeList = ''

data = {

"passengerTicketStr": passengerTicketStr,

"oldPassengerStr": oldPassengerStr,

"randCode": codeList,

"purpose_codes": "00",

"key_check_isChange": Func12306.keyIsChange,

"leftTicketStr": Func12306.leftTicketStr,

"train_location": Func12306.trainInfoLocationList[Func12306.trainIndexOfBuy],

"choose_seats": "",

"seatDetailType": "000",

"whatsSelect": "1",

"roomType": "00",

"dwAll": "N",

"_json_att": "",

"REPEAT_SUBMIT_TOKEN": Func12306.reSubmitTk

}

response=self.session.post(url=url,data=data, headers=self.headers, cookies=Func12306.cookies, verify=False)

try:

dic = loads(response.content)

except:

return "NetWorkError"

if 'data' in dic.keys():

if dic['data']['submitStatus'] is True:

print("提交訂單成功")

return True

elif dic['data']['errMsg'] == u"驗(yàn)證碼輸入錯(cuò)誤磷杏!":

return "wrongCode"

else:

print("提交訂單失敗")

return False

如果以上都成功了茴丰,就會(huì)進(jìn)入一個(gè)等待訂單生成了過(guò)程

def wait_time(self):

url='https://kyfw.12306.cn/otn/confirmPassenger/queryOrderWaitTime?random={}&tourFlag=dc&_json_att=&REPEAT_SUBMIT_TOKEN={}'.format(round(time.time()*1000),Func12306.reSubmitTk)

response=self.session.get(url=url,headers=self.headers, cookies=Func12306.cookies,verify=False)

try:

dic = loads(response.content)

except:

return "NetWorkError"

if dic['status']:

if dic['data']['queryOrderWaitTimeStatus']:

if dic['data']['waitTime'] > 0 :

return dic['data']['waitTime']

elif dic['data']['waitTime'] == -1:

Func12306.orderId = ''

Func12306.orderId = dic['data']['orderId']

return dic['data']['waitTime']

else:

return False

else:

return False

else:

return False

這里會(huì)有等待時(shí)間贿肩,我們獲取到等待時(shí)間汰规,然后再次發(fā)送這個(gè)請(qǐng)求溜哮,一直循環(huán),直到等待時(shí)間為-1就是購(gòu)票成功了 這個(gè)時(shí)候就可以開(kāi)心的去12306上查詢訂單然后付款

結(jié)語(yǔ)

和大家分享一下科阎,有興趣的小伙伴們可以去試試哦锣笨! 一方面是檢驗(yàn)一下自己的學(xué)習(xí)成果道批,另一方面也希望能幫你解決一下?lián)屍钡膯?wèn)題吧隆豹! 不過(guò)試試歸試試璃赡,還是要做2手準(zhǔn)備哦鉴吹。不要全部寄托在軟件的便利上面豆励,要經(jīng)過(guò)試驗(yàn)才知道能否成功。

很多細(xì)節(jié)在碼代碼的時(shí)候遇到技扼,但是現(xiàn)在總結(jié)可能就忘了說(shuō)剿吻,博客寫(xiě)的比較粗丽旅,沒(méi)有寫(xiě)得那么詳細(xì)榄笙。 最后茅撞,希望也在研究12306的朋友可以在這里有所收獲

最后,喜歡學(xué)習(xí)python可以關(guān)注我們哦

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市吁津,隨后出現(xiàn)的幾起案子腺毫,更是在濱河造成了極大的恐慌,老刑警劉巖邪蛔,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侧到,死亡現(xiàn)場(chǎng)離奇詭異匠抗,居然都是意外死亡汞贸,警方通過(guò)查閱死者的電腦和手機(jī)矢腻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)多柑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)竣灌,“玉大人初嘹,你說(shuō)我怎么就攤上這事削樊÷辏” “怎么了迅脐?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵谴蔑,是天一觀的道長(zhǎng)隐锭。 經(jīng)常有香客問(wèn)我钦睡,道長(zhǎng)荞怒,這世上最難降的妖魔是什么褐桌? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任荧嵌,我火速辦了婚禮啦撮,結(jié)果婚禮上逻族,老公的妹妹穿的比我還像新娘聘鳞。我一直安慰自己抠璃,他們只是感情好搏嗡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著蔚润,像睡著了一般嫡纠。 火紅的嫁衣襯著肌膚如雪除盏。 梳的紋絲不亂的頭發(fā)上者蠕,一...
    開(kāi)封第一講書(shū)人閱讀 51,573評(píng)論 1 305
  • 那天蠢棱,我揣著相機(jī)與錄音,去河邊找鬼量没。 笑死,一個(gè)胖子當(dāng)著我的面吹牛突想,可吹牛的內(nèi)容都是我干的殴蹄。 我是一名探鬼主播,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼猾担,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼袭灯!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起绑嘹,我...
    開(kāi)封第一講書(shū)人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤稽荧,失蹤者是張志新(化名)和其女友劉穎工腋,沒(méi)想到半個(gè)月后姨丈,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡擅腰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年蟋恬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片趁冈。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡歼争,死狀恐怖拜马,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情沐绒,我是刑警寧澤俩莽,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站洒沦,受9級(jí)特大地震影響豹绪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜申眼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一瞒津、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧括尸,春花似錦不恭、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至有送,卻和暖如春淌喻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背雀摘。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工裸删, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人阵赠。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓涯塔,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親清蚀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子匕荸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 【經(jīng)文】 凡所行的,都不要發(fā)怨言枷邪,起爭(zhēng)論榛搔,使你們無(wú)可指摘,誠(chéng)實(shí)無(wú)偽东揣,在這彎曲悖謬的世代药薯,作神無(wú)瑕疵的兒女。你們顯在...
    斐斐feifei閱讀 1,241評(píng)論 0 1
  • 劉潤(rùn)五分鐘:積極主動(dòng) 哦救斑,我不算是太積極的人童本,溫溫吞吞的慢節(jié)奏。 偶爾很積極脸候,就想著工作嘛穷娱,反正就擺在眼前绑蔫,早做...
    四月Fineyoga閱讀 137評(píng)論 0 0
  • 不聰明,不堅(jiān)強(qiáng)泵额,不會(huì)說(shuō)話配深,不會(huì)使眼色,不懂得人情世故嫁盲,不會(huì)謙虛的做事篓叶,更不懂得表達(dá)自己的感情,為人處事里羞秤,...
    初橙閱讀 404評(píng)論 0 0
  • 本文內(nèi)容基于 npm 4.0.5 概述 npm (node package manager)缸托,即 node 包管理...
    靜默虛空閱讀 2,137評(píng)論 0 8