春運到了,帶你用python來搶票回家!

来源:https://www.cnblogs.com/chengxyuan/archive/2020/01/04/12150024.html
-Advertisement-
Play Games

不知不覺,一年一度的春運搶票大幕已經拉開,想快速搶到回家的車票嗎?作為程式員,這些技術手段,你一定要知道。 為了讓大家更快捷更便利的搶火車票,各種各樣的搶票軟體應需而生,這類軟體大部分都是付費搶票的機制。 作為程式員,如何用技術手段搶到回家的票?來看看用 Python 寫的搶票腳本。 手把手教你用 ...


不知不覺,一年一度的春運搶票大幕已經拉開,想快速搶到回家的車票嗎?作為程式員,這些技術手段,你一定要知道。

為了讓大家更快捷更便利的搶火車票,各種各樣的搶票軟體應需而生,這類軟體大部分都是付費搶票的機制。

作為程式員,如何用技術手段搶到回家的票?來看看用 Python 寫的搶票腳本。

手把手教你用 Python 搶票回家過年

環境介紹

windows 8.1
python3.6.1
firefox插件 geckodriver.exe

操作步驟

引入要的模塊

        from selenium import webdriver      #控制瀏覽器
        from selenium.webdriver.common.keys import Keys  #用於給元素賦值
        import time   #時間模塊
        from selenium.webdriver.support.select import Select  #控制下拉框模塊
        from selenium.webdriver.common.by import By   #尋找元素模塊
        from selenium.webdriver.support.ui import WebDriverWait  #“顯示等待”模塊
        from selenium.webdriver.support import expected_conditions as EC  #等待條件模塊

 

登陸模塊

首先需要選擇使用的瀏覽器,此處以 firefox 為例,下載:geckodriver.exe 。

提到的 stations.txt 可以直接看這個:

車站信息:

https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9042

將 geckodriver.exe 放到 python.exe 同級目錄下即可(如果有報錯的情況下,放一個該文件到與 firefox.exe 同級目錄下,並添加環境變數)

        #可以用input,也可以直接放入到後面的用戶名、密碼輸入框中
        #可以利用標準輸入進行批量的操作,此處以個人搶票操作為例
        # username = str(input('請輸入你的用戶名:'))
        # password = str(input('請輸入你的密碼:'))  #這兩行可以暫時忽略

        browser = webdriver.Firefox()      #驅動firefox瀏覽器
        browser.get("https://kyfw.12306.cn/otn/login/init")    #啟動瀏覽器後進入該鏈接下
        browser.find_element_by_id('username').clear()
        browser.find_element_by_id('username').send_keys(‘xxxxx’)    #xxxxx更換為用戶名  
        browser.find_element_by_id('password').send_keys(‘xxxxx’)    #xxxxx更換為密碼   
        time.sleep(10)    #此時驗證碼自行點擊,該處設置10秒延遲,可以自己設置
        try:
                browser.find_element_by_id('loginSub').click()     #點擊登陸操作,該id為登陸按鈕
                #或者 browser.find_element_by_link_text('登陸').click()  #標簽顯示的名稱
        except:
                browser.find_element_by_class_name('touclick-bgimg touclick-reload touclick-reload-normal').click()     #try中驗證碼輸入點錯了會在此處刷新一次
                time.sleep(20)                     #第二次輸入驗證碼前等待20秒,可以自己設置,第一次輸入無誤直接跳過
                browser.find_element_by_id('loginSub').click()    #重新輸入驗證碼後的點擊登陸

 

跳轉模塊

#python學習群592539176
#預設跳轉到首頁
        time.sleep(2)    #此處一般無需設置時間等待,調試代碼時使用
        clickReserve = browser.find_element_by_link_text('車票預訂').click()  #跳轉到車票預定頁面,該頁面可以查詢票
        time.sleep(2)        #出發地點和到達地點設置
        #此處value值為出發時刻的地點,BJP表示北京,更改value值在頁面上不載入,基本不耗時間,從頁面中也看不到出發地和目的地
        #此處內容以爬取,保存在stations.txt中,每行表示一個地址,打開文檔ctrl + F查找即可
        jsf = 'var a = document.getElementById("fromStation");a.value = "BJP"'    #此處將BJP更換為你需要的出發地址,value值在以爬取到stations.txt中,自行查看
        browser.execute_script(jsf)
        jst = 'var a = document.getElementById("toStation");a.value = "LZJ"'   #終點,同上方法
        browser.execute_script(jst)
        js = "document.getElementById('train_date').removeAttribute('readonly')"    #時間選擇時預設為只讀,通過JS移除只讀屬性
        browser.execute_script(js)    #執行JS語句
        browser.find_element_by_id('train_date').clear()    #時間元素中預設有提示字,需要先清空
        browser.find_element_by_id('train_date').send_keys('2018-02-01')   #按照改格式輸入需要查詢的時間
        search = browser.find_element_by_id('query_ticket').click()    #輸入好信息時點擊查詢,該處存在成人票和學生票,預設是成人票,如果購買,對學生票處執行以下語句即可:
        #browser.find_element_by_id('xxxx').click()    #對於id還是class或其它自行選擇,[可以查看此處](http://blog.51cto.com/12376665/2052278)

 

開始購票

此處,就是點擊預定的操作,我在這裡只是舉一個方法例子,也可以通過不斷點擊直到成功(這樣可以避免網站倒計時和實際時間的時間差影響,但是不知道 12306 在搶票時對不斷快速訪問有沒有限制)。

  start_time = "Thu Jan 04 08:00:00 2018"    #首先設置需要搶票的時間
        b = time.mktime(time.strptime(start_time,"%a %b %d %H:%M:%S %Y"))        print(time.strftime("%a %b %d %H:%M:%S %Y", time.localtime(b)) )  #此處是為了調試代碼使用,可忽略,不影響使用
        a = float(b)-time.time()    #利用自己設置的時間減去當前時間的時間戳
        time.sleep(a)    #上一步驟得出的秒數就是需要等待搶票的時間
try:     #此處本來有try中的部分就夠了,WebDriverWait已有相應等待重覆訪問機制,預設為0.5秒試驗一次,except中添加是為了以防萬一
    WebDriverWait(browser,10).until(EC.presence_of_element_located((By.ID, "ticket_2400000Z550L")))   #查找需要預定的車次的id,直到出現,10表示共等待10秒
    ticket = browser.find_element_by_xpath('//tr[@id="ticket_2400000Z550L"]/td[13]/a').click()    #點擊預定按鈕except:
    browser.find_element_by_id('query_ticket').click()
    WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.ID, "ticket_2400000Z550L")))
    ticket = browser.find_element_by_xpath('//tr[@id="ticket_2400000Z550L"]/td[13]/a').click()
"""
normalPassenger_8 數字表示該賬號下的第幾位,預設從0開始如果是第一個則為normalPassenger_0
"""WebDriverWait(browser,10).until(EC.presence_of_element_located((By.ID, "normalPassenger_8")))
browser.find_element_by_id('normalPassenger_8').click()   #id中的8表示賬號下第九位s = Select(browser.find_element_by_id('seatType_1'))
s.select_by_value('6')    #此處value值看下方各個種類,6表示高級軟卧browser.find_element_by_id('submitOrder_id').click()
WebDriverWait(browser,10).until(EC.presence_of_element_located((By.ID, "qr_submit_id")))
browser.find_element_by_link_text('提交訂單')
browser.find_element_by_id('qr_submit_id').click()#-------------------------------------------------結束#硬座 1#硬卧 3#軟卧 4#高級軟卧 6#二等座 O(大寫字母)#一等座 M#商務座 9

 

總結

需要替換的地方:

  • 用戶名,密碼。

  • 起始地點和目的地的 value 值,查 stations.txt 修改即可。

  • 出發時間。

  • 自己選擇車次的 xpath 路徑,路徑不用變,變對應 id 即可。

  • 勾選用戶的位置(如果只要一個用戶,預設用:normalPassenger_0)。

  • 所選座位類別,預設為有票的類別里最便宜的種類。

其餘的在測試中都相同,沒有發現有變化,在使用前,可以測試一下代碼,測試是註意註釋掉提交訂單的代碼(下單有取消限制,每天好像只能取消三次),測試時網速正常。

有人說用瀏覽器執行速度會慢,確實對於可以直接識別驗證碼的腳本而言,沒有界面的會更快一些,但是實際上所用時間為預定開始到結束,相同網路下,代碼執行時間是要快於人工操作的,

另外,時間可以研究一下,之前研究過某寶的時間,秒殺時間是要比北京時間提前一點幾秒的,感覺全國各地有微小時間差的。

完整腳本示例

#python學習群592539176
#python3.6.1#data:2018-01-03#author:LGC247CG"""
說明:
1.該腳本主要是提供一個實現思路,實現方法有很多,可以優化的地方也有很多,觸發機制也可以自己設置,代碼以壓縮到最短,只是為了讓大家都可以看明白
2.正常網路狀況下,不設置指定時間時,從點擊確認驗證碼到下單基本上1秒左右,所以速度上還是沒問題的
3.由於同時勾選多人和單人使用所需時間基本相同,希望該方法只用於技術交流,請勿作為黃牛使用
4.在作為技術交流的情況下,如果驗證碼可以實現將可以完全實現自動搶票:
--1>驗證碼有一定規律和數量,可以利用腳本獲取所有圖片,並加上相應標簽
--2>將頁面的文字和標簽相匹配,再將圖片進行相似度計算,對對應圖片進行點擊操作
--3>或是訓練深度學習的圖片識別模型,通過演算法識別
"""from selenium import webdriverfrom selenium.webdriver.common.keys import Keysimport timefrom selenium.webdriver.support.select import Selectfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as EC

browser = webdriver.Firefox()
browser.get("https://kyfw.12306.cn/otn/login/init")
browser.find_element_by_id('username').clear()
browser.find_element_by_id('username').send_keys('xxxxxxx')
browser.find_element_by_id('password').send_keys('xxxxxxx')
time.sleep(10)try:
    browser.find_element_by_id('loginSub').click()except:
    browser.find_element_by_class_name('touclick-bgimg touclick-reload touclick-reload-normal').click()
    time.sleep(15)
    browser.find_element_by_id('loginSub').click()#跳轉到車票預定頁面time.sleep(2)
clickReserve = browser.find_element_by_link_text('車票預訂').click()#出發地點和到達地點設置WebDriverWait(browser,10).until(EC.presence_of_element_located((By.ID, "fromStation")))
jsf = 'var a = document.getElementById("fromStation");a.value = "BJP"'browser.execute_script(jsf)
jst = 'var a = document.getElementById("toStation");a.value = "LZJ"'browser.execute_script(jst)
js = "document.getElementById('train_date').removeAttribute('readonly')"browser.execute_script(js)
browser.find_element_by_id('train_date').clear()
browser.find_element_by_id('train_date').send_keys('2018-02-02')
search = browser.find_element_by_id('query_ticket').click()#對於時間,我一直覺得網站計算的時間和自己獲取的時間差一秒左右,這個根據不同環境自己測試start_time = "Thu Jan 04 10:00:00 2018"    #首先設置需要搶票的時間b = time.mktime(time.strptime(start_time,"%a %b %d %H:%M:%S %Y"))
print(time.strftime("%a %b %d %H:%M:%S %Y", time.localtime(b)) )  #此處是為了調試代碼使用,可忽略,不影響使用a = float(b)-time.time()    #利用自己設置的時間減去當前時間的時間戳time.sleep(a)    #上一步驟得出的秒數就是需要等待搶票的時間browser.find_element_by_id('query_ticket').click()    #時間到了先點擊查詢刷新一下,以防找不到元素try:
    WebDriverWait(browser,10).until(EC.presence_of_element_located((By.ID, "ticket_2400000Z550L")))
    ticket = browser.find_element_by_xpath('//tr[@id="ticket_2400000Z550L"]/td[13]/a').click()except:
    browser.find_element_by_id('query_ticket').click()
    WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.ID, "ticket_250000K8880L")))
    ticket = browser.find_element_by_xpath('//tr[@id="ticket_250000K8880L"]/td[13]/a').click()"""
normalPassenger_8 數字表示該賬號下的第幾位,預設從0開始如果是第一個則為normalPassenger_0
"""WebDriverWait(browser,10).until(EC.presence_of_element_located((By.ID, "normalPassenger_8")))
browser.find_element_by_id('normalPassenger_8').click()
s = Select(browser.find_element_by_id('seatType_1'))
s.select_by_value('6')
browser.find_element_by_id('submitOrder_id').click()
WebDriverWait(browser,10).until(EC.presence_of_element_located((By.ID, "qr_submit_id")))
browser.find_element_by_link_text('提交訂單')#browser.find_element_by_id('qr_submit_id').click()

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 問題: 最近在部署項目的時候出現數據亂碼的情況,經過一番查看項目都是用的UTF-8編碼格式,數據也是,但是經過調用介面傳給對方就亂碼了。 由於是部署在Windows環境下,Windows預設編碼GBK,這就導致了jvm運行時編碼不一致的問題,修改也很容易。 解決辦法: Linux環境下如果使用的UT ...
  • 1.參數會作為一個 Python 表達式(從技術上說是一個條件列表)被解析並求值 2.去除字元串兩邊的引號 srting 也可以用 3.字元串轉字典 4.傳遞全局變數 5.傳遞本地變數 ...
  • 1.python中函數的工作原理 python的解釋器,也就是python.exe(c編寫)會用PyEval_EvalFramEx(c函數)運行foo()函數 首先會創建一個棧幀(stack Frame),在棧幀對象的上下文裡面去運行這個位元組碼。 可以嘗試著去列印foo的位元組碼: 關於位元組碼的解釋: ...
  • python中的多線程其實並不是真正的多線程,如果想要充分地使用多核CPU資源,在python中大部分情況需要使用多進程。python提供了非常好用的多進程包Multiprocessing,只需要定義一個函數,python會完成其它所有事情。藉助這個包,可以輕鬆完成從單進程到併發執行的轉換。mult ...
  • 1 #include"stdio.h" 2 #include"stdlib.h" 3 #include"string.h" 4 #include"conio.h" 5 typedef struct node 6 { 7 char xh[11]; //學號 8 char xm[10]; //姓名 9 ...
  • 前言 本文轉自松哥(網名:江南一點雨)的一篇實用入門文章,寫的挺好的,希望對各位有所幫助。 什麼是面霸?就是在面試中,神擋殺神佛擋殺佛,見招拆招,面到面試官自慚形穢自嘆不如!松哥希望本文能成為你面霸路上的墊腳石! 做 Java 開發,沒有人敢小覷 Spring Boot 的重要性,現在出去面試,無論 ...
  • 什麼是Spring Spring是一個開源的,輕量級Java開發框架; 其核心特性是可以用於開發任何 Java 應用程式,Spring 框架的目標是使 JavaEE應用程式的開發變得更加容易,核心概念是IOC和AOP;這也是學習Spring的重點所在; Spring不是針對某個具體功能,具體層級的框 ...
  • 功能描述: 1)使用tkinter設計程式界面; 2)調用Windows API函數實現錄音機和音樂播放器。 。 參考代碼: ​ 運行界面: ​ ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...