Python版實現12306搶票功能,真的能幫你搶到春運回傢的票嗎?

背景

每逢佳節倍思親,年關將近,思鄉的情緒是不是愈發強烈瞭,筒子們是不是又要準備開始搶票瞭,還是在找黃牛嗎?但是,今年在考慮是否能搶到票以外,還需要考慮是否能回得去,沒錯,因為疫情,需要全國人民同心協力抗疫,咱不能給祖國媽媽添麻煩,隻希望皆大歡喜吧!

黃牛

它憑什麼,厲害得能’脫泥而出’搶到票,它是12306的內部人員?還是他傢的親戚?而且還那麼牛逼哄哄的要價,春節要加價100元/張,讓原本已經200元的票價就上漲70%,有什麼辦法解決這一現象嗎?有些也是通過買人傢工具的VIP功能(據說是按年續費的比較劃算),還有其他交通app的vip加價功能,嗯,作者是沒成功過!還幾乎跟黃牛一個價,還不如給黃牛省心。

自動搶票腳本

作為半個程序員的作者,有點’水土’不服,也嘗試過自己寫腳本來解決,但是有一年直接被那個圖片驗證碼給打敗,也就不瞭瞭之瞭,而在前不久又看到瞭別人特別推崇的搶票腳本,在github開源瞭,一看嚇一跳,star那麼高比作者的35星強的不是一個量級,最後作者也耐不住好奇心拿來一試深淺。

克隆代碼到本地

git clone https://github.com/testerSunshine/12306

首先閱讀README.md配置好python運行環境,該有的功能呢先不要偷工減料,按要求完成。

修改配置文件:TickerConfig

  • 自動打碼,設置為2
AUTO_CODE_TYPE = 2 # 聽他的吧,否則就是執行不下去瞭,即使是2也不影響;
  • 沒必要發送郵箱,設置False
EMAIL_CONF = {    "IS_MAIL": False,    "email": "",    "notice_email_list": "",    "username": "",    "password": "",    "host": "smtp.qq.com",}
  • 不配置selenium環境,設置COOKIE_TYPE=3
# 如果COOKIE_TYPE=3, 則需配置RAIL_EXPIRATION、RAIL_DEVICEID的值RAIL_EXPIRATION = ""RAIL_DEVICEID = ""
    • 值去哪裡找?瀏覽器訪問:https://www.12306.cn;打開F12–cookies右側欄就能找到瞭⬇⬇⬇

  • 關註微信提醒:SERVER_CHAN_CONF,可有可無
# 前往 http://sc.ftqq.com/3.version 掃碼綁定獲取 SECRETSERVER_CHAN_CONF = {    "is_server_chan": True,    "secret": "SCT76378TuaIlPCkz8OkWcUJwvlJoAe7Q"}

  • 其他配置項保持默認,隻替換乘車日期、預售時間、乘車人、班次信息即可。

開始運行:python run.py r

如果開啟代理,先將ip加到proxy_list執行:python run.py c

  • 哦豁,執行結果出票失敗瞭,這是不可能的,帳號本地測試能登錄提交訂單,不應該存在失敗;
  • 那麼隻能找源碼調試瞭:inter/SubmitOrderRequest文件.submitOrderRequest類.sendSubmitOrderRequest方法
def sendSubmitOrderRequest(self):    """    提交車次    預定的請求參數,註意參數順序    註意這裡為瞭防止secretStr被urllib.parse過度編碼,在這裡進行一次解碼    否則調用HttpTester類的post方法將會將secretStr編碼成為無效碼,造成提交預定請求失敗    :param secretStr: 提交車次加密    :return:    """    submit_station_url = self.session.urls["submit_station_url"]    submitResult = self.session.httpClint.send(submit_station_url, self.data_apr())    # print(submitResult) # 調試    if 'data' in submitResult and submitResult['data']:        if submitResult['data'] == "N":            coi = checkOrderInfo(self.session, self.train_no, self.set_type, self.passengerTicketStrList,                                 self.oldPassengerStr,                                 self.train_date, self.ticke_peoples)            coi.sendCheckOrderInfo()        else:            print (u'出票失敗')    elif 'messages' in submitResult and submitResult['messages']:        raise ticketIsExitsException(submitResult['messages'][0])

分析源碼

提交訂單請求的時候,在第二個if條件時直接跳過,走到else就over瞭,根本就沒檢查訂單,所以作者在外層print(submitResult)看看這個結果的data是啥?

  • ?excuse me,竟然是“0”,不是“N”
{'validateMessagesShowId': '_validatorMessage', 'status': True, 'httpstatus': 200, 'data': '0', 'messages': [], 'validateMessages': {}}
  • 懷疑:帳號肯定能正常查詢餘票並下單成功的,不可能存在購買不瞭,所以猜測是12306返回參數改變瞭,讓腳本沒有走訂票邏輯(畢竟是兩年前的代碼),所以改源碼,讓第二個if等於”0″,記得是字符串哦。
if submitResult['data'] == "0": # 原來的右邊條件是:"N"
  • 再次執行,結果如下,訂票成功!

  • 於是趕緊跑去12306的app查驗,果然有未支付的訂單,真是太厲害瞭。

拭目以待

本地運行代碼調試成功,隻待明日查看結果,是否會訂票成功,不然還是擺脫不瞭找黃牛的命運!!!

隻希望疫情得以控制,否則就算是有票,根據嚴重情況,都有可能把線路都停運瞭。