目錄
一、效果展示
二、代碼詳解
1 匯入庫
2 確定好購票基本資訊
3 登錄12306
4 模擬滑動滑塊
5 處理疫情特殊要求
6 點擊購票并填寫出發地、目的地、出發時間
7 鎖定車票
三、實作監控購買
注意
環境
代碼
大家有沒有這種感覺,一到國慶、春節這種長假,搶火車票就非常困難?各大互聯網公司都推出搶票服務,只要加錢給服務費就可以增加搶到票的幾率,有些火車票代售網點和一些加速買票軟體,說你只要給100元服務費就可以優先幫忙搶到票,
本文和你一起探索搶票軟體背后的原理,
很多人學習蟒蛇,不知道從何學起, 很多人學習尋找python,掌握了基本語法之后,不知道在哪里案例上手, 很多已經可能知道案例的人,卻不怎么去學習更多高深的知識, 這三類人,我給大家提供一個好的學習平臺,免費獲取視頻教程,電子書,以及課程的源代碼! QQ群:101677771 歡迎加入,一起討論學習
一、效果展示
在正式進入代碼講解之前,先來看下本文的實作效果,
如果不是為了演示效果,直接在最后確定階段加一個延時點擊確定,應該不到45秒可以鎖定一張票,只要在30分鐘之內付款即可,
二、代碼詳解
本小節會詳細解鎖搶票軟體是如何模擬登錄網站,進行自動買票的,為了更清晰地給大家展示,部分代碼沒有寫成函式,直接裸代碼運行,讓需要買票的朋友可以自己應用軟體進行購票,
1 匯入庫
首先匯入本文需要加載的庫,如果你有些庫還沒有安裝,導致運行代碼時報錯,可以在Anaconda Prompt中用pip方法安裝,
import json
import time
from captcha import *
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import wait
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support import expected_conditions as EC
#匯入庫
2 確定好購票基本資訊
匯入庫后,在python代碼中填寫你購票的基本資訊,
purpose = 'ADULT' #購買成人票,如果是學生票,需調整代碼
names = ['謝朝陽'] #填寫購票人姓名
date = '2021-09-21' #填寫購票日期
start_station = '深圳' #購票出發站
end_station = '長沙南' #購票目的站
password = '11234567xyz' #登錄12306的秘密
username ='xiezhaoyang122700' #登錄12306的賬號
trains = ['G1004', 'G80', 'G6028', 'G6182', 'G6016'] #你想買的班次
#填寫基本資訊
本文預訂的是2021年9月21日從深圳到長沙南的高鐵票,你可以根據自己的實際需要進行調整,由于有些班次的時間過早或過晚,買了也很不方便,所以可以在trains中挑選出你滿意的班次進行購票,在這里需要提醒大家,我之前在嘗試代碼時碰到的坑,那就是時間中如果有個位數要在前面填0,比如2021年9月2日,你在填寫購票日期date時要寫成'2021-09-02',否則在運行代碼時日期總是填不進去,
3 登錄12306
確定好購票的基本資訊后,就可以應用python模擬登錄12306了,代碼如下:
options = webdriver.ChromeOptions()
options.add_argument("--disable-blink-features=AutomationControlled")
browser = webdriver.Chrome(options=options)
browser.maximize_window()
login_url = 'https://kyfw.12306.cn/otn/resources/login.html'
#ticket_url = 'https://kyfw.12306.cn/otn/leftTicket/init'
browser.get(login_url)
time.sleep(0.5)
wait.WebDriverWait(browser, 5).until(EC.element_to_be_clickable((By.CLASS_NAME,'login-hd-account'))).click()
input_name = browser.find_element_by_id('J-userName')
input_pd = browser.find_element_by_id('J-password')
input_name.send_keys(username)
input_pd.send_keys(password)
login = browser.find_element_by_id('J-login')
login.click()
#登錄12306
整體思路是:?
1.應用python模擬呼叫google瀏覽器;
2.輸入12306網址;
3.等網頁加載完全后點擊賬戶密碼登錄;
4.找到賬號密碼的id,把賬戶密碼資訊填充進去;
5.找到登錄id,模擬點擊登錄按鈕,
在這一小節中要注意兩個點,
一、要在python安裝目錄中放和google版本匹配的chromedriver,供python呼叫,
二、要學會填寫賬戶密碼資訊的id,
首先,在google瀏覽器中輸入12306登錄網址:
中國鐵路12306
接著點擊賬戶密碼登錄,會出現如下界面:
然后點擊紅框中的三個點,找到更多工具,點擊開發者工具,會出現如下界面:
?
?
點擊紅框中的箭頭,把滑鼠移動到賬戶框上去,就會出現如下界面:
?
右邊變灰的框里就會出現對應的id,點擊賬號框,再把滑鼠移動到右邊變灰的字符上去,點擊右鍵,會出現copy element的選項,復制下來即可,
<input type="text" class="input" id="J-userName" placeholder="用戶名/郵箱/手機號" style="height: 44px; line-height: 44px; outline: black 0px;" aria-label="請輸入用戶名/郵箱/手機號" title="請輸入用戶名/郵箱/手機號">
發現了嗎?源代碼input_name中要填寫的
browser.find_element_by_id('J-userName')內容,即為id="J-userName"中的資訊,
4 模擬滑動滑塊
輸入完用戶名和密碼,點擊立即登錄后,會出現如下滑塊驗證要求,
?
運行如下代碼即可拖動滑塊進行驗證,
browser.implicitly_wait(5)
print('=====開始處理滑動驗證碼=====')
track = [300, 400, 500]
for i in track:
try:
btn = browser.find_element_by_xpath('//*[@id="nc_1__scale_text"]/span')
ActionChains(browser).drag_and_drop_by_offset(btn,i,0).perform()
except:
time.sleep(2)
#拉動滑塊驗證
其中,browser.implicitly_wait(5)表示隱性等待5秒,track中放的是滑塊拉動的距離,
5 處理疫情特殊要求
完成滑塊驗證要求后,會出現如下疫情特殊要求提示:
?
用如下代碼點擊確認即可,
browser.implicitly_wait(5)
browser.find_element_by_xpath('/html/body/div[5]/div[2]/div[3]/a').click()
time.sleep(2)
#疫情特殊要求
browser.find_element_by_xpath和id的區別是,在右鍵復制時要copy XPath或copy full XPath,
6 點擊購票并填寫出發地、目的地、出發時間
接下來是選擇買票,并將出發地、目的地、出發時間等資訊填寫進去,
browser.find_element_by_xpath('//*[@id="J-chepiao"]/a').click()
browser.find_element_by_xpath('//*[@id="megamenu-3"]/div[1]/ul/li[1]/a').click()
browser.find_element_by_xpath('//*[@id="qd_closeDefaultWarningWindowDialog_id"]').click()
#選擇買票
def input_info():
print('=====開始買票=====')
from_station = browser.find_element_by_xpath('//*[@id="fromStationText"]')
from_station.send_keys(Keys.ENTER)
from_station.send_keys(Keys.CONTROL, 'a')
from_station.send_keys(start_station, Keys.ENTER)
browser.implicitly_wait(5)
to_station = browser.find_element_by_xpath('//*[@id="toStationText"]')
to_station.send_keys(Keys.ENTER)
to_station.send_keys(Keys.CONTROL, 'a')
to_station.send_keys(end_station, Keys.ENTER)
browser.implicitly_wait(5)
start_date = browser.find_element_by_xpath('//*[@id="train_date"]')
start_date.send_keys(Keys.ENTER)
start_date.send_keys(Keys.CONTROL, 'a')
start_date.send_keys(Keys.CONTROL, 'x')
start_date.send_keys(date, Keys.ENTER)
browser.implicitly_wait(5)
wait.WebDriverWait(browser, 3).until(EC.element_to_be_clickable((By.ID,'query_ticket'))).click()
input_info()
input_info()
#將出發地、目的地、出發日期填進去
得到的結果如下:
?
這里需要注意的是我呼叫了兩遍input_info函式,因為12306可能采取了一些反爬措施,一遍輸入進去后查不出東西,顯示為灰色,
7 鎖定車票
最后是依次查找trains中的車次是否有票,有的話點擊購買鎖定車票,
trList = browser.find_elements_by_xpath(".//tbody[@id='queryLeftTable']/tr[not(@datatran)]")
for tr in trList:
trainNum = tr.find_element_by_class_name("number").text
if trainNum in trains:
leftTicket = tr.find_element_by_xpath(".//td[4]").text
print('leftTicket', leftTicket)
if leftTicket == '有' or leftTicket.isdigit():
orderBtn = tr.find_element_by_class_name("btn72")
orderBtn.click()
browser.implicitly_wait(5)
passengerLabels = browser.find_elements_by_xpath(".//ul[@id='normal_passenger_id']/li/label")
for passengerLabel in passengerLabels:
name = passengerLabel.text
if name in names:
passengerLabel.click()
browser.implicitly_wait(20)
# 獲取提交按鈕
submitBtn = browser.find_element_by_id("submitOrder_id")
submitBtn.click()
browser.implicitly_wait(20)
confirmBtn = browser.find_element_by_id("qr_submit_id")
confirmBtn.click()
time.sleep(2)
browser.implicitly_wait(20)
confirmBtn = browser.find_element_by_id("qr_submit_id")
confirmBtn.click()
break
#依次查找trains中的車次是否有票,有的話點擊購買
所以,如果你有特別心儀的車次,可以在trains中放在最前面,依次填寫覺得還行的車次,至此,應用python解鎖搶票軟體背后的原理已講解完畢,感興趣的朋友可以自己跟著本文實作一遍,
12306不定期會更新買票界面,所以過一段時間可能之前的代碼就要進行一些調整,需要自己弄清里面的原理,才可以以不變應萬變,本文的代碼沒有進行高級的封裝,只為大家能更清楚地了解每一步,能在搶票高峰期買到自己心儀的票,
也寫得很基礎,沒有進一步的調優縮短時效,感興趣的朋友可以自行研究,如有任何疑問可以跟我溝通,
三、實作監控購買
原代碼只能實作購票,我對代碼進行了修改,增加了監測和搶票成功推送功能,
需要自行輸入12306賬號、密碼,購買車次、時間、出發站、目的站、server醬key(Server醬·Turbo版 (ftqq.com)去申請)
經測驗可成功購票,但有如下問題需要
注意
1.登錄測驗過多可能會導致滑塊驗證失敗,可自行點擊重繪,即可自動執行后續代碼(懶得寫重繪驗證了,只要不是多次運行,一般不會有這個問題)
2.main()中,買票buy那一塊,因為我是要搶票,等待時間設定為2,如果是監測,建議設定時間長一點,因為有可能被反爬
3.買票提交按鈕可能會有bug,于是我在main中增加了一次選擇來確保,但無論如何,進入提交頁面你都會收到微信提示,為了保險,建議去看一下是否真的提交了,手動提交也不是不可以,
4.多人買票請在buy()函式下names里填入
5.代碼中那么多**code,是我用來標記這段代碼是否執行成功,如果沒有成功就重復執行,如果code=0,代碼沒成功,再從頭執行,gmcode和code感覺有點重復了,但是,管他呢,能運行就行了, 滑稽.jpg
6.我只是個業余程式猿,代碼改的丑陋,我盡量寫的通俗易懂了,大佬勿噴,
環境
(食用本代碼需要一定的基礎知識,新手估計挺難得)
- python3
- webdriver
以及一些庫,我用pycharm,沒有的庫可以直接匯入
還有,我覺得最主要的就是webdriver,自己有的話更好,配置的話可能需要很久時間,也挺麻煩的
代碼
# -*- coding:utf-8 -*-
import json
import requests
import time
from captcha import *
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import wait
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support import expected_conditions as EC
# 定義一系列code來確保每一步執行成功再進入下一步
global logincode, hkcode, yzcode, xpcode, cpcode, gmcode, code
# 初始化
def init_program():
options = webdriver.ChromeOptions()
options.add_argument("--disable-blink-features=AutomationControlled")
browser = webdriver.Chrome(options=options)
browser.maximize_window()
return browser
# 登錄12306
def login(browser):
global logincode
logincode = 0
password = '' # 登錄12306的秘密
username = '' # 登錄12306的賬號
login_url = 'https://kyfw.12306.cn/otn/resources/login.html'
# ticket_url = 'https://kyfw.12306.cn/otn/leftTicket/init'
try:
browser.get(login_url)
time.sleep(0.5)
wait.WebDriverWait(browser, 5).until(EC.element_to_be_clickable((By.CLASS_NAME, 'login-hd-code'))).click()
input_name = browser.find_element_by_id('J-userName')
input_pd = browser.find_element_by_id('J-password')
input_name.send_keys(username)
input_pd.send_keys(password)
login = browser.find_element_by_id('J-login')
login.click()
logincode = 1
except Exception as e:
logincode = 0
print(e)
# 拉動滑塊驗證
def huakuai(browser):
global hkcode
hkcode = 0
try:
browser.implicitly_wait(5)
print('=====開始處理滑動驗證碼=====')
track = [300, 400, 500]
for i in track:
try:
btn = browser.find_element_by_xpath('//*[@id="nc_1__scale_text"]/span')
ActionChains(browser).drag_and_drop_by_offset(btn, i, 0).perform()
hkcode = 1
except:
time.sleep(2)
except Exception as e:
hkcode = 0
print(e)
# 疫情特殊要求
def yiqingyaoqiu(browser):
global yzcode
yzcode = 0
try:
browser.implicitly_wait(5)
try:
browser.find_element_by_xpath('/html/body/div[4]/div[2]/div[3]/a').click()
yzcode = 1
except:
try:
browser.find_element_by_xpath('/html/body/div[2]/div[7]/div[2]/div[3]/a').click()
yzcode = 1
except:
yzcode = 0
finally:
time.sleep(2)
except Exception as e:
yzcode = 0
print(e)
# 進入買票頁面
def enterbuy(browser):
global xpcode
xpcode = 0
try:
browser.find_element_by_xpath('//*[@id="J-chepiao"]/a').click()
browser.find_element_by_xpath('//*[@id="megamenu-3"]/div[1]/ul/li[1]/a').click()
browser.find_element_by_xpath('//*[@id="qd_closeDefaultWarningWindowDialog_id"]').click()
xpcode = 1
except Exception as e:
print(e)
xpcode = 0
# 將出發地、目的地、出發日期填進去
def input_info(browser):
global cpcode
cpcode = 0
date = '2022-01-24' # 填寫購票日期
start_station = '' # 購票出發站,例如南京南
end_station = '' # 購票目的站
try:
print('=====開始買票=====')
from_station = browser.find_element_by_xpath('//*[@id="fromStationText"]')
from_station.send_keys(Keys.ENTER)
from_station.send_keys(Keys.CONTROL, 'a')
from_station.send_keys(start_station, Keys.ENTER)
browser.implicitly_wait(5)
to_station = browser.find_element_by_xpath('//*[@id="toStationText"]')
to_station.send_keys(Keys.ENTER)
to_station.send_keys(Keys.CONTROL, 'a')
to_station.send_keys(end_station, Keys.ENTER)
browser.implicitly_wait(5)
start_date = browser.find_element_by_xpath('//*[@id="train_date"]')
start_date.send_keys(Keys.ENTER)
start_date.send_keys(Keys.CONTROL, 'a')
start_date.send_keys(Keys.CONTROL, 'x')
start_date.send_keys(date, Keys.ENTER)
browser.implicitly_wait(5)
wait.WebDriverWait(browser, 3).until(EC.element_to_be_clickable((By.ID, 'query_ticket'))).click()
cpcode = 1
except Exception as e:
print(e)
cpcode = 0
# 依次查找trains中的車次是否有票,有的話點擊購買
def buy(browser):
global gmcode, code
gmcode = 0
code = 0
purpose = 'ADULT' # 購買成人票,如果是學生票,需調整代碼
names = [''] # 填寫購票人姓名,需要在你的乘車人管理里有的
trains = [] # 你想買的班次,例如'D666', 'G666'
browser.implicitly_wait(5)
try:
trList = browser.find_elements_by_xpath(".//tbody[@id='queryLeftTable']/tr[not(@datatran)]")
for tr in trList:
trainNum = tr.find_element_by_class_name("number").text
if trainNum in trains:
leftTicket = tr.find_element_by_xpath(".//td[4]").text
print('leftTicket', leftTicket)
if leftTicket == '有' or leftTicket.isdigit():
orderBtn = tr.find_element_by_class_name("btn72")
orderBtn.click()
browser.implicitly_wait(5)
passengerLabels = browser.find_elements_by_xpath(".//ul[@id='normal_passenger_id']/li/label")
for passengerLabel in passengerLabels:
name = passengerLabel.text
if name in names:
passengerLabel.click()
browser.implicitly_wait(20)
# 獲取提交按鈕
submitBtn = browser.find_element_by_id("submitOrder_id")
submitBtn.click()
browser.implicitly_wait(20)
confirmBtn = browser.find_element_by_id("qr_submit_id")
confirmBtn.click()
time.sleep(2)
browser.implicitly_wait(20)
confirmBtn = browser.find_element_by_id("qr_submit_id")
confirmBtn.click()
code = 1
gmcode = 1
break
except Exception as e:
print(e)
gmcode = 0
def tuisong():
api = "https://sctapi.ftqq.com/*****.send" #*****替換成你的微信server醬的key,可以實作購票成功推送,然后你就自己去12306付款
title = '購買成功'
data = https://www.cnblogs.com/sn5200/p/{
"text": title
}
req = requests.post(api, data=https://www.cnblogs.com/sn5200/p/data)
if __name__ == "__main__":
global logincode, yzcode, hkcode, xpcode, cpcode, gmcode, code
code = 0
logincode = 0
yzcode = 0
hkcode = 0
xpcode = 0
cpcode = 0
gmcode = 0
browser = init_program()
while code == 0:
while logincode == 0:
login(browser)
print('logincode:', logincode)
while hkcode == 0:
huakuai(browser)
print('hkcode:', hkcode)
while yzcode == 0:
yiqingyaoqiu(browser)
print('yzcode:', yzcode)
while xpcode == 0:
enterbuy(browser)
print('xpcode:', xpcode)
while cpcode == 0:
input_info(browser)
input_info(browser)#經測驗,一次有可能不成功,我直接兩次提交
print('cpcode:', cpcode)
while gmcode == 0:
buy(browser)
print('gmcode:', gmcode)
print('code:', code)
if gmcode == 0:
browser.refresh()
time.sleep(2)
browser.find_element_by_xpath('//*[@id="qd_closeDefaultWarningWindowDialog_id"]').click()
input_info(browser)
input_info(browser)
else:
try:
print('tijiao')
confirmBtn = browser.find_element_by_id("qr_submit_id")
browser.implicitly_wait(20)
time.sleep(3)
confirmBtn.click()
except:pass
if code == 1:
tuisong()
break
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/412877.html
標籤:Python
