1. 程式人生 > >python+splinter實現12306網站刷票並自動購票流程

python+splinter實現12306網站刷票並自動購票流程

python+splinter實現12306網站刷票並自動購票流程

通過python+splinter,實現在12306網站刷票並自動購票流程(無法自動識別驗證碼)。

此類程式只是提高了12306網站的 <查詢> 重新整理頻率(預設自動查詢的重新整理頻率為5秒)。對於學習splinter感覺還是不錯的,但是想通過裝個類似刷票程式成功購票的 還是多花點錢升級升級硬體裝置,提高提高網速吧。

程式寫的有點亂,隨時修改ing。

#!/usr/bin/env python3
# encoding: utf-8
  
from splinter.browser import browser
import time
  
#12306的賬號,密碼
user_name = 'xxxxxxxxxx' #自行修改
pass_word = 'xxxxxxxxxx'
  
# 通過splinter,登入12306網站(登入驗證碼需要手動驗證)
b = browser(driver_name = 'firefox') # 設定火狐瀏覽器
b.visit('https://kyfw.12306.cn/otn/leftticket/init') # 開啟12306介面
b.find_by_id(u'login_user') # 點選登入按鈕
  
b.fill('loginuserdto.user_name',user_name) # 填寫賬號
b.fill('userdto.password',pass_word) # 填寫密碼
  
# 手動填寫驗證碼並登入,登入成功後等待自動跳轉到購票頁面。
'''
跳轉頁面過程中:
程式可能會報錯:[winerror 10053] 您的主機中的軟體中止了一個已建立的連線。
原因:未知
解決辦法:寫一個迴圈,程式不停的嘗試連結跳轉頁面(總會成功),成功後跳出迴圈。
'''
while true:
  if b.url == 'https://kyfw.12306.cn/otn/index/initmy12306': # 判斷是否登入成功
    try:
      b.visit('https://kyfw.12306.cn/otn/leftticket/init') # 訪問購票頁面
    except connectionabortederror: #捕捉可能出現的異常,繼續訪問
      b.visit('https://kyfw.12306.cn/otn/leftticket/init')
    if b.url == 'https://kyfw.12306.cn/otn/leftticket/init': # 判斷是否跳轉購票頁面成功
      break
  
# 新增、載入cookies資訊,查詢餘票。(自動添加出發地、目的地、日期,例如:北京-鄭州)
b.cookies.add({'_jc_save_fromdate':'2018-08-11'}) # 出發日期
b.cookies.add({'_jc_save_fromstation':u'%u5317%u4eac%2cbjp'}) # 出發站資訊(北京)
b.cookies.add({'_jc_save_todate':'2018-08-11'}) # 到達日期
b.cookies.add({'_jc_save_tostation':u'%u90d1%u5dde%2czzf'}) # 目的地資訊(鄭州)
b.reload() # 重新載入cookies
b.find_by_text(u'查詢').click() #點選查詢
  
# 新增車次型別
l = ['gc-高鐵/城際','d-動車','z-直達','t-特快','k-快速','其他']#在列表裡可以去掉不需要的車次型別
for i in l:
  btn = b.find_by_text(i)
  btn.click()
   
# 下拉訂票幫手(此步驟可跳過) 
b.find_by_id(u'show_more').click()
  
  
# 設定坐席
def the_seat():
  
  '''
  新增坐席後,網站會自動勾選<自動提交>、<自動查詢>功能。
  <自動查詢> 預設的是5秒重新整理一次(慢),所以我們要關閉此選項,提高重新整理頻率。
  '''
  seat =['二等座','軟臥','硬臥','硬座','無座'] #設定一個坐席列表
  b.find_by_xpath('/html/body/div[6]/div[5]/div[2]/div[7]/div[2]/span/a').click()#開啟坐席選擇的選單視窗
  for i in seat:
    b.find_by_name(i).click() #新增坐席
  b.find_by_xpath('/html/body/div[11]/div[1]/a').click()#關閉彈窗
  b.find_by_text(u'開啟自動查詢').click()# 點選關閉<自動查詢>選項(慢)。關閉自動查詢功能後,自動提交功能也會關閉。
  
  
# 購票
def train_ticket_purchase():
   
  the_seat() #設定坐席
  b.find_by_id(u'show_more').click() # 關閉訂票幫手(此步驟可跳過)
  
  #查詢訂票
  while b.url != 'https://kyfw.12306.cn/otn/confirmpassenger/initdc': #以預訂成功跳轉頁面為判斷條件
    try:
      b.find_by_text(u'查詢').click() # 點選查詢
      if b.is_element_present_by_text(u'預訂') == true: #判斷是否有<預訂>
        for i in b.find_by_text(u'預訂'): # b.fin_by_text(u'預訂'),返回包含<預訂>元素的列表,其中有些可以點選‘預訂'購票,有些‘預訂'顯灰色無票狀態,無法點選預訂購票的。
          if i.has_class('btn72'): #篩選<預訂>元素,區分可以點選預訂的和不可以點選的(可以點選<預訂>的元素,都包含屬性class('btn72'))
            i.click()#點選預訂購票
           
            if b.is_element_present_by_xpath('//*[@id="content_defaultwarningalert_hearder"]') == true: #可能會彈窗提示:當前時間不可預訂
              b.find_by_xpath('//*[@id="gb_closedefaultwarningwindowdialog_id"]').click() # 關閉提示彈窗
              print('當前時間不可預訂,請關閉程式稍後再執行。')
              break
  
            if b.is_element_present_by_xpath('//*[@id="content_defaultwarningalert_title"]') == true: #可能會彈窗提示:您選擇的列車距開車時間很近了,請確保有足夠的時間抵達車站,並辦理換取紙質車票、安全檢查、實名制驗證及檢票等手續,以免耽誤您的旅行。
              b.find_by_xpath('//*[@id="qd_closedefaultwarningwindowdialog_id"]').click() #關閉彈窗(注意:關閉彈窗,但是仍然會購票)
             
            b.find_by_text(u'xxx')[1].click() #自行新增乘車人名字(注意:登入賬號本人的名字元素可能會有兩個(一個賬號,一個乘車人),注意區分開)
            b.find_by_text(u'提交訂單').click()
  
            #確認訂單(不知道為什麼 b.find_by_xpath()方法不行。。。。)
            b.find_by_css('html body#body_id.dhtmlx_winviewport.dhtmlx_skin_dhx_terrace div.dhtmlx_window_active div.dhtmlx_wins_body_outer div.dhtmlx_wins_body_inner.dhtmlx_wins_no_header div div#checkticketinfo_id div#content_checkticketinfo_id.up-box.w664 div.up-box-bd.ticket-check div#confirmdiv.lay-btn a#qr_submit_id.btn92s').click()
            print('預訂成功,退出程式')
            break
          else:
            print('暫時沒票,繼續查詢中...')
      else:
        print('暫時沒票,繼續查詢中...')     
    except:
      print('不可預訂,請稍後再次執行程式...')
      break
  
  
if __name__ == '__main__':
  train_ticket_purchase()