python3.7之12306搶票指令碼實現
阿新 • • 發佈:2019-01-08
悲催的12306,徹底淪為各路搶票軟體的服務提供方。元旦伊始,純粹12306官網及APP搶票,愈一週的時間,僅到手一張凌晨3:55回家的站票。為遠離腦殘,無奈選擇搶票軟體,預購年後返滬車票。BTW,研究一下搶票指令碼的實現思路,參考:(https://juejin.im/post/5b116504f265da6e0636cbc2 - Python3.6實現12306火車票自動搶票)。
在原作者之上,對執行程式碼做了以下處理:
- 刪除簡訊/郵件通知功能
- 刪除控制檯輸入功能
- 新增登陸cookie的重新整理
- 新增多車次搶票
- 新增多座位型別搶票
注:使用 splinter.browser
程式碼如下:
#!/usr/bin/env python # -*- coding: utf-8 -*- from splinter.browser import Browser from time import sleep import sys class BrushTicket(object): """買票類及實現方法""" def __init__(self, passengers, from_time, from_station, to_station, number_seat):"""定義例項屬性,初始化""" # 乘客姓名 self.passengers = passengers # 起始站和終點站 self.from_station = from_station self.to_station = to_station # 乘車日期 self.from_time = from_time # 車次 - 座位 dict num_seat_dic = {} for num_seat in number_seat: use= num_seat.split(':') num = use[0] seats = use[1] seats_use = seats.split(',') seat_str = '' for seat in seats_use: # 座位型別所在td位置 if seat == '商務座特等座': seat_type_index = 1 seat_type_value = 9 elif seat == '一等座': seat_type_index = 2 seat_type_value = 'M' elif seat == '二等座': seat_type_index = 3 seat_type_value = 0 elif seat == '高階軟臥': seat_type_index = 4 seat_type_value = 6 elif seat == '軟臥': seat_type_index = 5 seat_type_value = 4 elif seat == '動臥': seat_type_index = 6 seat_type_value = 'F' elif seat == '硬臥': seat_type_index = 7 seat_type_value = 3 elif seat == '軟座': seat_type_index = 8 seat_type_value = 2 elif seat == '硬座': seat_type_index = 9 seat_type_value = 1 elif seat == '無座': seat_type_index = 10 seat_type_value = 1 elif seat == '其他': seat_type_index = 11 seat_type_value = 1 else: seat_type_index = 7 seat_type_value = 3 seat_str += (str(seat_type_index) + '-' + str(seat_type_value) + ',') num_seat_dic[num] = seat_str self.num_seat_dic = num_seat_dic # 新版12306官網主要頁面網址 self.login_url = 'https://kyfw.12306.cn/otn/resources/login.html' self.init_my_url = 'https://kyfw.12306.cn/otn/view/index.html' self.ticket_url = 'https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc' # 瀏覽器驅動資訊,驅動下載頁:https://sites.google.com/a/chromium.org/chromedriver/downloads self.driver_name = 'chrome' self.driver = Browser("chrome") def do_login(self): """登入功能實現,手動識別驗證碼進行登入""" self.driver.visit(self.login_url) sleep(1) # 選擇登陸方式登陸 print('請掃碼登陸或者賬號登陸……') while True: if self.driver.url != self.init_my_url: sleep(1) else: break def start_brush(self): """買票功能實現""" # 瀏覽器視窗最大化 self.driver.driver.maximize_window() # 登陸 self.do_login() # 跳轉到搶票頁面 self.driver.visit(self.ticket_url) try: print('開始刷票……') # 載入車票查詢資訊 self.driver.cookies.add({"_jc_save_fromStation": self.from_station}) self.driver.cookies.add({"_jc_save_toStation": self.to_station}) self.driver.cookies.add({"_jc_save_fromDate": self.from_time}) self.driver.reload() count = 0 while self.driver.url == self.ticket_url: self.driver.find_by_text('查詢').click() sleep(1) count += 1 print('第%d次點選查詢……' % count) if count % 50 == 0: self.driver.find_by_id('login_user').click() sleep(1) self.driver.visit(self.ticket_url) sleep(1) print('繼續刷票......') # 載入車票查詢資訊 self.driver.cookies.add({"_jc_save_fromStation": self.from_station}) self.driver.cookies.add({"_jc_save_toStation": self.to_station}) self.driver.cookies.add({"_jc_save_fromDate": self.from_time}) self.driver.reload() if self.driver.url == self.ticket_url: continue try: # 多車次處理 for bander in self.num_seat_dic.keys(): current_tr = self.driver.find_by_xpath('//tr[@datatran="' + bander + '"]/preceding-sibling::tr[1]') if current_tr: # 多座次處理 seat_value = self.num_seat_dic[bander] seat_split = seat_value.split(',') for seat in seat_split: if seat: seat_type = seat.split('-') seat_type_index = int(seat_type[0]) seat_type_value = int(seat_type[1]) if current_tr.find_by_tag('td')[seat_type_index].text == '--': print(bander + ' 還未出售') sleep(1) elif current_tr.find_by_tag('td')[seat_type_index].text == '無': print(bander + ' 無票,繼續嘗試……') sleep(1) else: # 有票,嘗試預訂 print(bander + ' 刷到票了(餘票數:' + str( current_tr.find_by_tag('td')[seat_type_index].text) + '),開始嘗試預訂……') current_tr.find_by_css('td.no-br>a')[0].click() sleep(1) key_value = 1 for p in self.passengers: # 選擇使用者 print('開始選擇使用者……') self.driver.find_by_text(p).last.click() # 選擇座位型別 print('開始選擇席別……') if seat_type_value != 0: self.driver.find_by_xpath( "//select[@id='seatType_" + str(key_value) + "']/option[@value='" + str( seat_type_value) + "']").first.click() key_value += 1 sleep(0.2) if p[-1] == ')': self.driver.find_by_id('dialog_xsertcj_ok').click() print('正在提交訂單……') self.driver.find_by_id('submitOrder_id').click() sleep(2) # 檢視放回結果是否正常 submit_false_info = self.driver.find_by_id('orderResultInfo_id')[0].text if submit_false_info != '': print(submit_false_info) self.driver.find_by_id('qr_closeTranforDialog_id').click() sleep(0.2) self.driver.find_by_id('preStep_id').click() sleep(0.3) continue print('正在確認訂單……') self.driver.find_by_id('qr_submit_id').click() print('預訂成功,請及時前往支付……') else: print('不存在當前車次【%s】,已結束當前刷票,請重新開啟!' % self.number) sys.exit(1) except Exception as error_info: print(error_info) except Exception as error_info: print(error_info) if __name__ == '__main__': # nya passengers=['***'] # 使用者名稱 from_time='2019-02-01' # 出發日期 from_station='%u4E0A%u6D77%2CSHH' # 起始站點 - 來自12306 餘票查詢 請求 - cookie (此處 - 上海) to_station='%u6C11%u6743%2CMQF' # 結束站點 (此處 - 民權) number_seat=['K4054:硬座,無座','K4168:硬座,無座'] # 車次:座位型別 # 開始搶票 ticket = BrushTicket(passengers, from_time, from_station, to_station, number_seat) ticket.start_brush()