臨近春節和期末放假,很多小夥伴也開始關注起來了12306的放票與搶票,學習python之餘,敲一個小的demo,如果能幫到人成功搶到票,那便是最好不過的了。這個小的腳本完成過程中,做了很多的調試,力求滿足所有人的條件。但是沒有在關鍵搶票環時間點拿出來使用過,所以如果有人能試用下,記得留言給我反饋,感謝!
其實這個腳本就是模擬的鼠標點擊與鍵盤輸入而已,原理很簡單,但是卻從輸入到點擊都提升了很多檔次,尤其是輸入。還有就是在搶票開始前幾分鐘就可以打開腳本,他會一直檢測你需要的車次與刷新界面,直到官方開放搶票接口的那一刻,都在不停檢測。
實現步驟
- 配置python + splinter環境,本人本次使用的是python2.7 + splinter0.7.7,splinter直接pip install即可。
- 瀏覽器 +WebDriver。建議Chrome + ChromeDriver。由於我本機Chrome位置移動最後未能識別到,索性就使用了splinter默認的瀏覽器Firefox + FirefoxDriver 。
- Chrome瀏覽器可自行下載,附上[瀏覽器驅動ChromeDriver]。(http://npm.taobao.org/mirrors/chromedriver/ “瀏覽器驅動ChromeDriver”)鏈接。
- 瀏覽器驅動下載下來是一個.exe執行文件,將其放在你本機python環境的目錄下,也就是跟python.exe同一目錄。要是找不到你的python環境,可以去環境變量中尋找。
注意點
- Chrome 與驅動ChromeDriver 應該兼容,與splinter也應該兼容。我這裏均使用的最新版本,打開上面的ChromeDriver網址,找到LATEST_RELEASE,下載並打開,會顯示最新的ChromeDriver是哪個版本,然後下載最新版中的chromedriver_win32.zip,Mac跟Linux當然對應其他的驅動.zip包)。
- 如果安裝完畢後會報錯,可能的原因有:版本不對不兼容;python環境不對,anaconda多環境的要注意下;驅動安裝位置不對;瀏覽器的問題,試試重裝最新版等。
半自動搶票代碼實現
具體的實現邏輯比較簡單,是splinter的基礎練手內容,畢竟是初學者,在這裏我就給大家講一下我實現的搶票代碼的使用方式,運行過後大家也可以試着改成自己想要的樣子。
- 上述環境等操作完成。
- 根據自己的情況修改代碼中的賬號密碼等數值,(雖然是python的初學者,但是沒有將其寫成一個接口,深感羞愧)。
- 運行代碼,唯一需要做的就是選擇登錄程序中的驗證碼,點擊登錄。如果自身瀏覽器比較慢的話,可能在個人界面卡一下,我並沒有在代碼上優化這一點,所以有的時候可能需要你手動點擊一下車票預訂(在後期可以試着寫一下對驗證碼的識別,不過應該是比較難的,畢竟360在這上面花了那麼多功夫,到時候再看)。
- 實現的功能有:查詢,預定,是否學生票,爲朋友預定,他們是否學生票。最後自行選座位之後,點擊最後一個提交按鈕。
5.爲什麼是說半自動搶票呢?不是在於最後一步的自己選座位(我給選也不太好),而是在於要自己去找對應車站的cookie信息,比如重慶——濰坊,重慶的cookie是 %u91CD%u5E86%2CCQW ,濰坊的cookie是 %u6F4D%u574A%2CWFK 。怎麼找呢?步驟如下:
- Chrome打開12306官網的查詢餘票界面
- 選中出發點,或者目的地,按下F12,找到Application,點擊Cookies看到的name/value就是對應的站點cookie信息。如圖,框後對應的value就是對應的cookie。
詳細代碼
# -*- coding: utf-8 -*-
from splinter.browser import Browser
from time import sleep
# 以下是你需要根據自己情況修改的數值
# 可以提前試一下,免得到時候因爲自己的輸入或者網絡太慢/瀏覽器太慢出現問題
# 搶到搶不到很大程度上依賴於機器和網絡的好壞
my_name = "孫良龍(學生)" # 你要搶票的人的名字,注意格式。當然名字要提前在12306上存檔的。
myfriends_name1 = "XXX(學生)" # 如果同時也給朋友搶的話,可以修改這一欄,沒有的話不要修改,修改會報錯
myfriends_name2 = "XXX(學生)" # 如果同時也給朋友搶的話,可以修改這一欄,沒有的話不要修改,修改會報錯
myfriends_name3 = "XXX(學生)" # 如果同時也給朋友搶的話,可以修改這一欄,沒有的話不要修改,修改會報錯
ticket_type = "普通票" # 你是要買學生票還是普通票
friend_ticket_type1 = "學生票" # 你的朋友1是要買學生票還是普通票
friend_ticket_type2 = "學生票" # 你的朋友2是要買學生票還是普通票
friend_ticket_type3 = "學生票" # 你的朋友3是要買學生票還是普通票
my_username = "[email protected]" # 換成你的用戶名
my_password = "sun651066702" # 換成你的密碼
my_time = "2018-02-06" # 選擇要搶票的日期,就算12306上面不可選也可以填 注意格式一定要與示例相同
train_num = 5 # 選擇車次,按照在12306上面的次序,比如上海—太原的Z196,train_num爲6,起始爲0
train_from = "%u7AE0%u4E18%2CZTK" # 選擇你的始發站,這是示例重慶
train_to = "%u6F4D%u574A%2CWFK" # 選擇你的終點站,這是示例濰坊
# 起始地址的cookies值要自己去找,尋找你的始終站的方法:http://www.sunlianglong.cn/index.php/2018/01/07/python01/
# 12306
login_url = "https://kyfw.12306.cn/otn/login/init"
my_url = "https://kyfw.12306.cn/otn/index/initMy12306"
ticket_url = "https://kyfw.12306.cn/otn/leftTicket/init"
buy = "https://kyfw.12306.cn/otn/confirmPassenger/initDc"
driver = Browser()
driver.visit(login_url)
# username password
driver.fill("loginUserDTO.user_name", my_username)
driver.fill("userDTO.password", my_password)
print(u"等待驗證碼,自行輸入...")
while True:
if driver.url != my_url:
sleep(1)
else:
break
driver.find_by_text(u"車票預訂").first.click()
while True:
if driver.url != ticket_url:
sleep(1)
else:
break
# To determine if a single interface has been entered
flag = 0
while flag == 0:
# 填寫出發點目的地
driver.cookies.add({u"_jc_save_fromStation": train_from})
driver.cookies.add({"_jc_save_fromDate": my_time})
driver.cookies.add({u"_jc_save_toStation": train_to})
# loading
driver.reload()
order = 1
if order != 0:
while True:
driver.find_by_text(u"查詢").click()
try:
noDate2 = driver.find_by_id("qd_closeDefaultWarningWindowDialog_id")
if noDate2 == []:
wait = driver.find_by_text(u"預訂")[train_num]
if wait == []:
break
else:
wait.click()
# To determine whether a successful reservation
if driver.url != buy:
order = order-1
else:
break
except Exception as e:
print u"還沒開始預訂"
continue
if order == 0:
flag = 1
break
print flag
if True:
# Choose yourself
driver.find_by_text(my_name).click()
stu_toast = driver.find_by_id("dialog_xsertcj_ok")
if stu_toast != [] :
if ticket_type == "學生票":
stu_toast.click()
else:
driver.find_by_id("dialog_xsertcj_cancel").click()
# Choose friend 1
if myfriends_name1 != "XXX(學生)":
driver.find_by_text(myfriends_name1).click()
stu_toast1 = driver.find_by_id("dialog_xsertcj_ok")
if stu_toast1 != []:
if friend_ticket_type1 == "學生票":
stu_toast1.click()
else:
driver.find_by_id("dialog_xsertcj_cancel").click()
# Choose friend 2
if myfriends_name2 != "XXX(學生)":
driver.find_by_text(myfriends_name2).click()
stu_toast2 = driver.find_by_id("dialog_xsertcj_ok")
if stu_toast2 != []:
if friend_ticket_type2 == "學生票":
stu_toast2.click()
else:
driver.find_by_id("dialog_xsertcj_cancel").click()
# Choose friend 3
if myfriends_name3 != "XXX(學生)":
driver.find_by_text(myfriends_name3).click()
stu_toast3 = driver.find_by_id("dialog_xsertcj_ok")
if stu_toast3 != []:
if friend_ticket_type3 == "學生票":
stu_toast3.click()
else:
driver.find_by_id("dialog_xsertcj_cancel").click()
while True:
driver.find_by_text(u"提交訂單").click()
if driver.url != buy:
break
print "success!"