? ? ? ? 大家好,我是好學(xué)的小師弟,由于沒搶到中秋回家的票,所以我寫了這個腳本,還有些模塊沒有完善,后期會補(bǔ)上。寫這個主要是用來加強(qiáng)自己對selenium和python的學(xué)習(xí)理解。該腳本僅供大家學(xué)習(xí)參考,輔助大家理解selenium知識。
目錄
一、鐵路12306登錄
1.反爬蟲
2.滑塊驗(yàn)證碼問題解決
3.登錄模塊完整代碼
二、出發(fā)地,目的地,乘車日期的選擇
1.乘車日期、出發(fā)地、目的地代碼思路和遇到的問題
2.乘車日期、出發(fā)地、目的地模塊代碼
三、購票、搶票模塊
1.流程概述
2.目前程序存在的缺點(diǎn)
3.程序難點(diǎn)(對我個人而言)?
4.搶票、購票模塊代碼
四、選座模塊
五、其他
1.查詢余票頁面,顯示頁面超時
2.pycharm與界面的切換
六、完整代碼
2021.9.24? 更新
一、鐵路12306登錄
首先我們打開12306的頁面,中國鐵路12306。發(fā)現(xiàn)頁面是需要二維碼登陸的,所以我們要在代碼里,先去選擇點(diǎn)擊賬號密碼登錄。
? ? ? ? ? ? ?
1.反爬蟲
這里如果你直接輸入賬號密碼,是不會顯示出驗(yàn)證碼來的,直接給你報錯。輸入以下代碼即可解決問題
script = 'Object.defineProperty(navigator,"webdriver",{get:()=>undefined,});'
driver.execute_script(script)
在代碼里輸入賬號和密碼后,會出現(xiàn)驗(yàn)證碼。這里的驗(yàn)證碼是滑塊驗(yàn)證碼,所以我們可以通過selenium的鼠標(biāo)事件來執(zhí)行。
from selenium.webdriver import ActionChains #導(dǎo)入鼠標(biāo)事件
2.滑塊驗(yàn)證碼問題解決
思路:?先確定滑塊的初始位置元素,選中它,然后模擬鼠標(biāo)按住不放,向右平移拖動一定的距離,即可完成驗(yàn)證。驗(yàn)證后,釋放鼠標(biāo),不然后面鼠標(biāo)就用不了了(一直會處在這個命令執(zhí)行狀態(tài)中)。記得perform()執(zhí)行,這個指令不能忘
代碼:? ? ? ?? ? ??
#滑動驗(yàn)證碼
#定位驗(yàn)證碼的頭位置元素
time.sleep(1)
picture_start=driver.find_element_by_id('nc_1_n1z')
#移動到相應(yīng)的位置,并左鍵鼠標(biāo)按住往右邊拖
ActionChains(driver).move_to_element(picture_start).click_and_hold(picture_start).move_by_offset(300,0).release().perform()
效果圖:
? ? ? ? ? ? ? ? ? ???
3.登錄模塊完整代碼
from selenium import webdriver
import time
from selenium.webdriver import ActionChains #導(dǎo)入鼠標(biāo)事件
from selenium.webdriver.common.keys import Keys #鍵盤功能鍵封裝的一個函數(shù)
driver=webdriver.Chrome() #驅(qū)動
url='https://kyfw.12306.cn/otn/resources/login.html' #鐵路12306網(wǎng)址
driver.get(url)
#反爬蟲
script = 'Object.defineProperty(navigator,"webdriver",{get:()=>undefined,});'
driver.execute_script(script)
#窗口最小化
driver.minimize_window()
driver.find_element_by_xpath('//*[@id="toolbar_Div"]/div[2]/div[2]/ul/li[2]/a').click()#點(diǎn)擊賬號密碼登錄
x=input('---輸入你的用戶名---\n')
driver.find_element_by_id('J-userName').send_keys(x)
y=input('---輸入你的密碼---\n')
driver.find_element_by_id('J-password').send_keys(y)
time.sleep(0.5)
driver.find_element_by_id('J-login').click()
#窗口最大化
driver.maximize_window()
#滑動驗(yàn)證碼
#定位驗(yàn)證碼的頭位置元素
time.sleep(1)
picture_start=driver.find_element_by_id('nc_1_n1z')
#移動到相應(yīng)的位置,并左鍵鼠標(biāo)按住往右邊拖
ActionChains(driver).move_to_element(picture_start).click_and_hold(picture_start).move_by_offset(300,0).release().perform()
#驗(yàn)證成功后,頁面會出現(xiàn)一個窗口 把他叉掉或者確定掉
time.sleep(3)
try:
driver.find_element_by_class_name("modal-close").click()
time.sleep(1)
except:
print('---程序正在運(yùn)行---')
driver.find_element_by_xpath('//*[@id="J-index"]/a').click()
#最小化窗口
driver.minimize_window()
time.sleep(1)
二、出發(fā)地,目的地,乘車日期的選擇
1.乘車日期、出發(fā)地、目的地代碼思路和遇到的問題
登陸成功后,我們就來到了出發(fā)地,目的地和乘車日期的選擇界面。這里我們用到了selenium的封裝keys函數(shù),keys函數(shù)可以用來調(diào)用鍵盤上的一些功能鍵,比如control,enter,backspace等。通過keys函數(shù)我們就可以做到把輸入文本框里的內(nèi)容,全選+刪除,然后輸入我們想要的出發(fā)日期,目的地,出發(fā)地。
?注意:這里的出發(fā)日期是含有下拉框的,你輸入你想要的日期之后,下拉框還是不會消失,下拉框不消失,他就會覆蓋到你的查詢按鈕,從而導(dǎo)致你click不到查詢這個元素,無法完成接下來的操作,程序會報錯。這個時候你點(diǎn)擊空白處,下拉框才會消失,但是selenium中我沒定位到空白區(qū)域的元素(或者就是壓根沒有?懷疑中),所以我找了另一個方法,點(diǎn)擊靜態(tài)圖片,因?yàn)樗麄儧]有超鏈接,也就相當(dāng)于空白區(qū)域,從而達(dá)到使得下拉框消失的目的,讓程序可以接著運(yùn)行。
2.乘車日期、出發(fā)地、目的地模塊代碼
here_place=input('---你的出發(fā)地---\n')
driver.find_element_by_xpath('//*[@id="fromStationText"]').clear()
driver.find_element_by_xpath('//*[@id="fromStationText"]').send_keys(here_place)
time.sleep(0.5)
driver.find_element_by_xpath('//*[@id="fromStationText"]').send_keys(Keys.ENTER)
there_place=input('---你的目的地---\n')
driver.find_element_by_xpath('//*[@id="toStationText"]').clear()
driver.find_element_by_xpath('//*[@id="toStationText"]').send_keys(there_place)
driver.find_element_by_xpath('//*[@id="toStationText"]').send_keys(Keys.ENTER)
#買哪天的票,出發(fā)日期填寫
travel_date=input('由于疫情目前12306只支持提前15天買票\n出發(fā)日期格式:20xx-05-07\n')
#頁面最大化
#driver.maximize_window()
time.sleep(1)
driver.find_element_by_xpath('//*[@id="train_date"]').send_keys(Keys.CONTROL,'a') #control+a全選
time.sleep(1)
driver.find_element_by_xpath('//*[@id="train_date"]').send_keys(Keys.BACKSPACE)
time.sleep(1)
driver.find_element_by_xpath('//*[@id="train_date"]').send_keys(travel_date)
driver.find_element_by_xpath('//*[@id="train_date"]').click()
time.sleep(1)
print('等待中')
time.sleep(0.5)
try:
#不能一次性點(diǎn)到鏈接,那就中間再點(diǎn)兩次無用的靜態(tài)文字
driver.find_element_by_xpath('//*[@id="toolbar_Div"]/div[4]/div[3]/div[1]/h3').click()
time.sleep(2)
driver.find_element_by_xpath('//*[@id="index_ads"]').click()
time.sleep(2)
# 點(diǎn)擊頁面上的靜態(tài)圖片(沒有內(nèi)含超鏈接),為了把上面車票的日期下拉框給去掉
driver.find_element_by_xpath('//*[@id="toolbar_Div"]/div[5]/div[1]/div/h2').click()
except:
driver.find_element_by_xpath('//*[@id="index_ads"]').click()
time.sleep(2)
#點(diǎn)擊頁面上的靜態(tài)圖片(沒有內(nèi)含超鏈接),為了把上面車票的日期下拉框給去掉
driver.find_element_by_xpath('//*[@id="toolbar_Div"]/div[5]/div[1]/div/h2').click()
time.sleep(2)
driver.find_element_by_xpath('//*[@id="search_one"]').click()
#叉掉疫情提示
time.sleep(2)
三、購票、搶票模塊
1.流程概述
12306每次都是在固定時間出售票的,一般是早上8點(diǎn)或者下午5點(diǎn)(時間有可能有變化,看情況)。所以,我們只需要在程序中加一個定時模塊就OK了,提前3分鐘執(zhí)行程序,就完成了搶票功能。
來說說購票
思路:點(diǎn)擊查詢按鈕,先詢問購票人是否需要購買學(xué)生票,然后輸入你想要乘坐的車次,這里我預(yù)選的是二等座,如果你想要乘坐硬座,列表[]里寫入15,我記得好象是,你可以把返回的字符串列表,打印出來,然后一個個數(shù),看硬座所對應(yīng)的位置是列表[]多少,然后改一下就行了。
查詢余票會出現(xiàn)兩種情況:
1.如果有余票,直接幫你預(yù)定,程序跳到下一步選座模塊。
2.沒有余票了或者票還沒發(fā)售,程序開始不停的點(diǎn)擊查詢按鈕,一旦發(fā)售或者有票,立刻幫你預(yù)定上(這里我好像只設(shè)置了運(yùn)行30秒,我覺得30秒沒搶到票,基本也沒戲了。。。>-<)搶到票,就跳到選座模塊;搶不到,瀏覽器直接退出。
2.目前程序存在的缺點(diǎn)
如果12306的頁面搜索出現(xiàn)兩行同名稱的列車車次,并且你想乘坐這輛車,他只會選中第一輛車
目前只支持購買一個人的票,并且是乘車人列表出現(xiàn)的第一個人
3.程序難點(diǎn)(對我個人而言)?
1.xpath的元素定位
/? 絕對定位??
//相對定位
.? 當(dāng)前節(jié)點(diǎn)
.//a[@id='蘇州']? ?當(dāng)前節(jié)點(diǎn)的相對位置下 a標(biāo)簽中的屬性為id的,且id的值為蘇州的xpath路徑
通過這種純手寫的xpath路徑方法,可以更快的獲得我們想要的元素
如果我們f12,點(diǎn)擊元素,右鍵copy中選擇xpath,往往得到的是含有通配符的//*[@id='蘇州'],這種方法,往往只能獲取到一個元素,但我們想要爬的是一個列表,所以這種方法在這個時候,就不是那么合適。
2.字符串如何變成列表?
我們爬下來的所乘日期當(dāng)天的班次是字符串,所以我們需要把字符串變?yōu)榱斜?。不然的話,不好定位,不好寫輸出哪個值
兩種方法
第一種? 分-總形式
自己定義一個空列表,然后for in 遍歷;空列表進(jìn)行追加,把車次,二等座,硬座,余票等等這些全部挨個建列表,然后再通過一個for in遍歷找到你所想要的那個車次,看循環(huán)第幾遍找到,然后列表輸出那個數(shù)字-1,這樣子就找到了,我們想要的信息了
第二種方法? 總—split函數(shù)—>字符串列表
直接把當(dāng)天的班次,全部打印出來,找共同點(diǎn),通過split函數(shù)對他們進(jìn)行切片,分割。split返回的即是字符串列表。這個更方便一點(diǎn)
3.邏輯思考
這里就是if else? ?try except? 這些邏輯上的編寫, 還有break的循環(huán)跳出 ,還有就是自定義函數(shù)的編寫調(diào)用。這點(diǎn)就是要考慮的場景太多了,耗時間和邏輯太多。。。所以我直接把場景設(shè)置死了,但是還是會有很多可能性。。。
4.搶票、購票模塊代碼
#看乘車人是否為學(xué)生,是否想購買學(xué)生票
def student():
stu=input('是否購買學(xué)生票,請輸入是或否\n')
if stu=='否':
driver.find_element_by_xpath('//*[@id="query_ticket"]').click()
accept_stu='已選擇成人票'
else:
stu_element=driver.find_element_by_xpath('//*[@id="sf2"]')
stu_element.click()
time.sleep(1)
driver.find_element_by_xpath('//*[@id="query_ticket"]').click()
accept_stu='已勾選購買學(xué)生票'
return accept_stu
student()
time.sleep(1)
#還沒開始售票,在不斷點(diǎn)擊預(yù)定按鈕
def refresh_search_ticket(train_message,train_number):
for times in range(0,31):
success_message=''
if times<30:
driver.find_element_by_xpath('//*[@id="query_ticket"]').click()
time.sleep(1)
if'有'==train_message[10]or'有'==train_message[9]:
print('---您選的車次二等座有票了,正在為您預(yù)定---')
time.sleep(0.5)
button = train_number.find_element_by_xpath('.//a[@class="btn72"]') # 已經(jīng)鎖定車次,對當(dāng)前車次進(jìn)行車票預(yù)定
time.sleep(0.5)
button.click()
# .//a[@class="btn72"]意思就是取a標(biāo)簽的屬性為class的值為btn72的元素xpath
time.sleep(1)
success_message='---預(yù)定成功,現(xiàn)在正在選擇乘車人---'
print('---預(yù)定成功,現(xiàn)在正在選擇乘車人---')
break
else:
print('繼續(xù)點(diǎn)擊查詢按鈕,刷新余票',end='\r')
else:
time.sleep(1)
success_message='---查詢時間已到!抱歉,您所選的車次,目前沒有二等座的票了,您可去12306官網(wǎng),繼續(xù)查詢---'
time.sleep(0.5)
print('---查詢時間已到!抱歉,您所選的車次,目前沒有二等座的票了,您可去12306官網(wǎng),繼續(xù)查詢---')
break
return success_message
def order_ticket():
train_num=input('---輸入你想乘坐的火車車次---\n')
train_numbers = driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr[not(@datatran)]')
#記得在元素element后面加s,因?yàn)橛泻枚鄠€元素,這里定位的是不含datatran的所有元素
for train_number in train_numbers:
order_ticket_message=''
train_messages=train_number.text.replace('\n',' ')#把換行符替換成空格
train_message=train_messages.split(' ')
'''
split():拆分字符串。通過指定分隔符對字符串進(jìn)行切片,并返回分割后的字符串列表(list)
'''
if train_num==train_message[0]:
print('---找到你想要的車次了---')
if'有'==train_message[10]or'有'==train_message[9]:#這里的列表數(shù)值,各個車可能有出入,到時候大家打印下整個車次列表,然后再改下數(shù)字就行了
print('---該車次現(xiàn)在有二等座---')
time.sleep(1)
button=train_number.find_element_by_xpath('.//a[@class="btn72"]')#已經(jīng)鎖定車次,對當(dāng)前車次進(jìn)行車票預(yù)定
button.click()
#.//a[@class="btn72"]意思就是取a標(biāo)簽的屬性為class的值為btn72的元素xpath
time.sleep(1)
order_ticket_message='預(yù)定成功,現(xiàn)在正在選擇乘車人'
print('預(yù)定成功,現(xiàn)在正在選擇乘車人')
break
else:
print('---抱歉,您所選的車次車票,目前沒票了,存在有候補(bǔ)票這種情況,正在為你刷新頁面,實(shí)時更新車票情況---')
result='---查詢時間已到!抱歉,您所選的車次,目前沒有二等座的票了,您可去12306官網(wǎng),繼續(xù)查詢---'
time.sleep(1)
success_messages=refresh_search_ticket(train_message,train_number)
if result==success_messages:
time.sleep(1)
order_ticket_message='---本次搶票已結(jié)束,祝你好運(yùn)---'
print('---本次搶票已結(jié)束,祝你好運(yùn)---')
break
else:
order_ticket_message='查到票了,預(yù)定成功,開始選乘坐人'
print('查到票了,預(yù)定成功,開始選乘坐人')
break
else:
print('---正在查詢你所需要的車次---',end='\r') #覆蓋前面一句---正在查詢你所需要的車次---,不然每循環(huán)一次,就會打印一次這句話
return order_ticket_message
finally_message=order_ticket()
if finally_message=='---本次搶票已結(jié)束,祝你好運(yùn)---':
print('---即將關(guān)閉瀏覽器打開的所有窗口---')
driver.quit()
time.sleep(1)
print('---瀏覽器已關(guān)閉---')
else:
time.sleep(2)
# 點(diǎn)擊乘車人信息,默認(rèn)第一個為本人
driver.find_element_by_xpath('//*[@id="normalPassenger_0"]').click()
print('---乘車人選擇成功,默認(rèn)選擇12306上面乘車人列表的第一位---')
time.sleep(0.5)
點(diǎn)擊提交訂單
driver.find_element_by_xpath('//*[@id="submitOrder_id"]').click()
四、選座模塊
因?yàn)?2306每天只有3次機(jī)會退票,好象是。所以我沒法多測試這個模塊到底行不行。。。。
#選座,報錯預(yù)警>_< 。。??赡軙婕暗骄W(wǎng)絡(luò)超時問題
print('---窗戶 A B C 過道 D F窗戶---')
time.sleep(1)
seat=input('---輸入你想要的位置,如果沒有該位置,隨機(jī)為你選擇一個位置---\n---輸入格式:place_X---\n---X為A B C D F---\n')
time.sleep(1)
seat_A='//*[@id="1A"]' #座位
seat_B='//*[@id="1B"]'
seat_C='//*[@id="1C"]'
seat_D='//*[@id="1D"]'
seat_F='//*[@id="1F"]'
decision_true='//*[@id="qr_submit_id"]' #確定按鈕
pay_money='---沒有自己想要選擇的位置了,隨機(jī)!---'
try:
seat=='place_A'
driver.find_element_by_xpath(seat_A).click()
time.sleep(1)
driver.find_element_by_xpath(decision_true).click()
pay_money = '---選座成功!寶貝,快來付錢---'
print('---選座成功!寶貝,快來付錢---')
time.sleep(1)
seat = 'place_A'
except:
driver.find_element_by_xpath(seat_A).click()
time.sleep(1)
print('你選的不是位置A/沒有位置A了')
time.sleep(1)
try:
seat == 'place_B'
driver.find_element_by_xpath(seat_B).click()
time.sleep(1)
driver.find_element_by_xpath(decision_true).click()
pay_money = '---選座成功!寶貝,快來付錢---'
print('---選座成功!寶貝,快來付錢---')
time.sleep(1)
seat = 'place_B'
except:
time.sleep(1)
print('你選的不是位置B/沒有位置B了')
time.sleep(1)
try:
seat=='place_C'
driver.find_element_by_xpath(seat_C).click()
time.sleep(1)
driver.find_element_by_xpath(decision_true).click()
pay_money = '---選座成功!寶貝,快來付錢---'
print('---選座成功!寶貝,快來付錢---')
time.sleep(1)
seat = 'place_C'
except:
time.sleep(1)
print('你選的不是位置C/沒有位置C了')
time.sleep(1)
try:
seat=='place_D'
driver.find_element_by_xpath(seat_D).click()
time.sleep(1)
driver.find_element_by_xpath(decision_true).click()
pay_money = '---選座成功!寶貝,快來付錢---'
print('---選座成功!寶貝,快來付錢---')
time.sleep(1)
seat = 'place_D'
except:
time.sleep(1)
print('你選的不是位置D/沒有位置D了')
time.sleep(1)
try:
seat=='place_F'
driver.find_element_by_xpath(seat_F).click()
time.sleep(1)
driver.find_element_by_xpath(decision_true).click()
pay_money = '---選座成功!寶貝,快來付錢---'
print('---選座成功!寶貝,快來付錢---')
time.sleep(1)
seat = 'place_F'
except:
time.sleep(1)
print('你選的不是位置F/沒有位置F了')
time.sleep(1)
if pay_money !='---選座成功!寶貝,快來付錢---':
print(pay_money)
driver.find_element_by_xpath(decision_true).click()
time.sleep(1)
print('15分鐘內(nèi),快去掃碼付錢!')
else:
print('15分鐘內(nèi),快去掃碼付錢!')
pay_result=input('---付款是否成功,選擇是或否---')
if pay_result=='是':
driver.quit()
else:
print('---selenium不穩(wěn)定---')
五、其他
1.查詢余票頁面,顯示頁面超時
晚上10點(diǎn)后,12306pc網(wǎng)頁就不太行了,一直顯示超時,所以我們就盡量不要在這個時候去登陸,我也寫了一個刷新函數(shù),有效果,雖然解決了這個頁面超時問題,但是選座的時候,還會出現(xiàn)新的網(wǎng)絡(luò)超時問題。。。。
2.pycharm與界面的切換
在pycharm下方出現(xiàn) '等待中' 以后的那個查詢余票界面,要切出來到pycharm中繼續(xù)寫你的需求,這個切換,最好用tab+alt。
六、完整代碼
from selenium import webdriver
import time
from selenium.webdriver import ActionChains #導(dǎo)入鼠標(biāo)事件
from selenium.webdriver.common.keys import Keys #鍵盤功能鍵封裝的一個函數(shù)
'''
by csdn 好學(xué)的小師弟
博客:https://blog.csdn.net/weixin_43784564
新人小白,歡迎大家一起學(xué)習(xí),交流,互相進(jìn)步
注:本文目前還差一個定時執(zhí)行任務(wù)腳本,且目前只支持選擇含有二等座選項(xiàng)的車次,購買的也是二等座。
如果12306的頁面搜索出現(xiàn)兩行同名稱的列車車次,這個程序就會報錯
目前只支持購買一個人的票
目前只測出這些bug,還有好多種乘車情況沒考慮,因?yàn)檫壿嬏嗔?,寫不來了,白天要打? >_<
如果想要自動執(zhí)行,就把input寫死,然后加個定時執(zhí)行腳本就行了
注意:12306網(wǎng)頁晚上10點(diǎn)左右好像就不靈光了,打開有困難,一直顯示頁面超時
頁面和pycharm之間切換,用tab+alt
如果報錯,要么就是網(wǎng)絡(luò)問題、又要你重新登陸了,多試幾次
要么就是selenium不穩(wěn)定。
要么就是我寫的程序有問題,邏輯出錯??上覜]時間去測試改了
(主要是選座的那一塊,我發(fā)博客之前零食寫的,沒時間了,tfs一堆任務(wù)要去忙)
白天打工太累了。。。。。
如果這個腳本對大家學(xué)習(xí)selenium和python有幫助的話,大家可以寫一個完善版
如果程序一直報錯,那就把選座模塊注釋掉,再運(yùn)行;
我昨晚試了下沒有選座模塊的程序,是能正常運(yùn)行的。
選座模塊是我今天中午吃飯的時候?qū)懙模€沒來得及測試。
本腳本,僅用來讓大家互相交流學(xué)習(xí),大家一起共同進(jìn)步!
'''
driver=webdriver.Chrome() #驅(qū)動
url='https://kyfw.12306.cn/otn/resources/login.html' #鐵路12306網(wǎng)址
driver.get(url)
#反爬蟲
script = 'Object.defineProperty(navigator,"webdriver",{get:()=>undefined,});'
driver.execute_script(script)
#窗口最小化
driver.minimize_window()
driver.find_element_by_xpath('//*[@id="toolbar_Div"]/div[2]/div[2]/ul/li[2]/a').click()#點(diǎn)擊賬號密碼登錄
x=input('---輸入你的用戶名---\n')
driver.find_element_by_id('J-userName').send_keys(x)
y=input('---輸入你的密碼---\n')
driver.find_element_by_id('J-password').send_keys(y)
time.sleep(0.5)
driver.find_element_by_id('J-login').click()
#窗口最大化
driver.maximize_window()
#滑動驗(yàn)證碼
#定位驗(yàn)證碼的頭位置元素
time.sleep(1)
picture_start=driver.find_element_by_id('nc_1_n1z')
#移動到相應(yīng)的位置,并左鍵鼠標(biāo)按住往右邊拖
ActionChains(driver).move_to_element(picture_start).click_and_hold(picture_start).move_by_offset(300,0).release().perform()
#有頁面有個窗口 把他叉掉或者確定掉
time.sleep(3)
try:
driver.find_element_by_class_name("modal-close").click()
time.sleep(1)
except:
print('---程序正在運(yùn)行---')
driver.find_element_by_xpath('//*[@id="J-index"]/a').click()
#最小化窗口
driver.minimize_window()
time.sleep(1)
here_place=input('---你的出發(fā)地---\n')
driver.find_element_by_xpath('//*[@id="fromStationText"]').clear() #清除對話框原內(nèi)容,這里用的是clear函數(shù)
driver.find_element_by_xpath('//*[@id="fromStationText"]').send_keys(here_place)#輸入你的出發(fā)地
time.sleep(0.5)
#因?yàn)?2306輸入出發(fā)地存在一個下拉框問題,所以這里我們使用keys這個封裝好的函數(shù),來調(diào)用鍵盤上的回車鍵,這樣就避免了鼠標(biāo)點(diǎn)擊空白處 這個操作
driver.find_element_by_xpath('//*[@id="fromStationText"]').send_keys(Keys.ENTER)
there_place=input('---你的目的地---\n')
driver.find_element_by_xpath('//*[@id="toStationText"]').clear()
driver.find_element_by_xpath('//*[@id="toStationText"]').send_keys(there_place)
driver.find_element_by_xpath('//*[@id="toStationText"]').send_keys(Keys.ENTER)
#買哪天的票,出發(fā)日期填寫
travel_date=input('由于疫情目前12306只支持提前15天買票\n出發(fā)日期格式:20xx-05-07\n')
time.sleep(1)
#這里用的是keys函數(shù),調(diào)用ctrl+a全選,然后按刪除鍵,刪除原對話框內(nèi)容
driver.find_element_by_xpath('//*[@id="train_date"]').send_keys(Keys.CONTROL,'a') #control+a全選
time.sleep(1)
driver.find_element_by_xpath('//*[@id="train_date"]').send_keys(Keys.BACKSPACE)
time.sleep(1)
driver.find_element_by_xpath('//*[@id="train_date"]').send_keys(travel_date)
driver.find_element_by_xpath('//*[@id="train_date"]').click()
time.sleep(1)
print('等待中')
time.sleep(0.5)
'''
這里注意,就算你輸入了訂票日期,下拉框也依舊存在,這里我們使用以下方法,解決這個問題,詳細(xì)解釋
https://blog.csdn.net/weixin_43784564/article/details/120352680
'''
try:
#不能一次性到鏈接,那就中間再點(diǎn)兩次無用的靜態(tài)文字
driver.find_element_by_xpath('//*[@id="toolbar_Div"]/div[4]/div[3]/div[1]/h3').click()
time.sleep(2)
driver.find_element_by_xpath('//*[@id="index_ads"]').click()
time.sleep(2)
# 點(diǎn)擊頁面上的靜態(tài)圖片(沒有內(nèi)含超鏈接),為了把上面車票的日期下拉框給去掉
driver.find_element_by_xpath('//*[@id="toolbar_Div"]/div[5]/div[1]/div/h2').click()
except:
driver.find_element_by_xpath('//*[@id="index_ads"]').click()
time.sleep(2)
#點(diǎn)擊頁面上的靜態(tài)圖片(沒有內(nèi)含超鏈接),為了把上面車票的日期下拉框給去掉
driver.find_element_by_xpath('//*[@id="toolbar_Div"]/div[5]/div[1]/div/h2').click()
time.sleep(2)
driver.find_element_by_xpath('//*[@id="search_one"]').click()
#叉掉疫情提示
time.sleep(2)
'''
為什么要獲得窗口句柄,詳細(xì)解釋詳見我上一條csdn博客https://blog.csdn.net/weixin_43784564/article/details/120368372
'''
# 獲取打開的多個窗口句柄
windows = driver.window_handles
# 切換到當(dāng)前最新打開的窗口
driver.switch_to.window(windows[-1])
time.sleep(2)
#窗口最大化
driver.maximize_window()
time.sleep(2)
#這里打開頁面會有一個溫馨提示,把他叉掉
try:
driver.find_element_by_xpath('//*[@id="gb_closeDefaultWarningWindowDialog_id"]').click()
except:
print('---這個溫馨提示我沒叉掉/不存在溫馨提示---')
#現(xiàn)在來到了購票頁面,點(diǎn)擊查詢按鈕
#這里出現(xiàn)一個問題,會出現(xiàn)頁面查詢超時,所以我們應(yīng)該搞個功能,即點(diǎn)擊按鈕,直到出現(xiàn)車次情況?。?!用到自己寫的一個函數(shù)
driver.find_element_by_xpath('//*[@id="query_ticket"]').click()
time.sleep(2)
driver.minimize_window()
time.sleep(2)
driver.find_element_by_xpath('//*[@id="query_ticket"]').click()
time.sleep(2)
#如果頁面查詢超時,就用下面這個函數(shù)
def refresh_yemian():
successful_search = ''
try:
time.sleep(1)
driver.find_element_by_xpath('//*[@id="float"]/th[1]').click()
time.sleep(1)
successful_search='---查詢頁面正常,可正常查詢車次---'
time.sleep(1)
except:
print('---正在點(diǎn)擊查詢按鈕---',end='\r')
time.sleep(1)
driver.find_element_by_xpath('//*[@id="query_ticket"]').click()
time.sleep(1)
refresh_yemian()
return successful_search
refresh_yemian()
time.sleep(1)
#看乘車人是否為學(xué)生,是否想購買學(xué)生票
def student():
stu=input('是否購買學(xué)生票,請輸入是或否\n')
if stu=='否':
driver.find_element_by_xpath('//*[@id="query_ticket"]').click()
accept_stu='已選擇成人票'
else:
stu_element=driver.find_element_by_xpath('//*[@id="sf2"]')
stu_element.click()
time.sleep(1)
driver.find_element_by_xpath('//*[@id="query_ticket"]').click()
accept_stu='已勾選購買學(xué)生票'
return accept_stu
student()
time.sleep(1)
#注意,本搶票腳本只適用于開始售票的那幾分鐘有用,畢竟搶票就搶那幾分鐘
#注意,本搶票腳本還差一個定時執(zhí)行任務(wù)腳本。需要你定個時
#定義一個函數(shù),如果發(fā)現(xiàn)目前頁面沒票了,就不斷刷新頁面,給你查詢是否有票現(xiàn)在.
def refresh_search_ticket(train_message,train_number):
for times in range(0,31):
success_message=''
if times<30:
driver.find_element_by_xpath('//*[@id="query_ticket"]').click()
time.sleep(1)
if'有'==train_message[10]or'有'==train_message[9]:
print('---您選的車次二等座有票了,正在為您預(yù)定---')
time.sleep(0.5)
button = train_number.find_element_by_xpath('.//a[@class="btn72"]') # 已經(jīng)鎖定車次,對當(dāng)前車次進(jìn)行車票預(yù)定
time.sleep(0.5)
button.click()
# .//a[@class="btn72"]意思就是取a標(biāo)簽的屬性為class的值為btn72的元素xpath
time.sleep(1)
success_message='---預(yù)定成功,現(xiàn)在正在選擇乘車人---'
print('---預(yù)定成功,現(xiàn)在正在選擇乘車人---')
break
else:
print('繼續(xù)點(diǎn)擊查詢按鈕,刷新余票',end='\r')
else:
time.sleep(1)
success_message='---查詢時間已到!抱歉,您所選的車次,目前沒有二等座的票了,您可去12306官網(wǎng),繼續(xù)查詢---'
time.sleep(0.5)
print('---查詢時間已到!抱歉,您所選的車次,目前沒有二等座的票了,您可去12306官網(wǎng),繼續(xù)查詢---')
break
return success_message
#輸入你想乘坐的車次,訂票
def order_ticket():
train_num=input('---輸入你想乘坐的火車車次---\n')
train_numbers = driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr[not(@datatran)]')
#記得在元素element后面加s,因?yàn)橛泻枚鄠€元素,這里定位的是不含datatran的所有元素
for train_number in train_numbers:
order_ticket_message=''
train_messages=train_number.text.replace('\n',' ')#把換行符替換成空格
train_message=train_messages.split(' ') #split切割函數(shù),用' '來切片,并返回字符串列表
if train_num==train_message[0]:
print('---找到你想要的車次了---')
if'有'==train_message[10]or'有'==train_message[9]:#這里的列表數(shù)值,各個車可能有出入,到時候大家打印下整個車次列表,然后再改下數(shù)字就行了,一般來說是不用改的
print('---該車次現(xiàn)在有二等座---')
time.sleep(1)
button=train_number.find_element_by_xpath('.//a[@class="btn72"]')#已經(jīng)鎖定車次,對當(dāng)前車次進(jìn)行車票預(yù)定
button.click()
#.//a[@class="btn72"]意思就是取當(dāng)前節(jié)點(diǎn),相對路徑下的a標(biāo)簽的屬性為class的值為btn72的元素xpath
time.sleep(1)
order_ticket_message='預(yù)定成功,現(xiàn)在正在選擇乘車人'
print('預(yù)定成功,現(xiàn)在正在選擇乘車人')
break
else:
print('---抱歉,您所選的車次車票,目前沒票了,存在有候補(bǔ)票這種情況,正在為你刷新頁面,實(shí)時更新車票情況---')
result='---查詢時間已到!抱歉,您所選的車次,目前沒有二等座的票了,您可去12306官網(wǎng),繼續(xù)查詢---'
time.sleep(1)
#沒票了,現(xiàn)在調(diào)用不斷刷新頁面的函數(shù),來給你查詢余票,并返回值
success_messages=refresh_search_ticket(train_message,train_number)
if result==success_messages:
time.sleep(1)
order_ticket_message='---本次搶票已結(jié)束,祝你好運(yùn)---'
print('---本次搶票已結(jié)束,祝你好運(yùn)---')
break
else:
order_ticket_message='查到票了,預(yù)定成功,開始選乘坐人'
print('查到票了,預(yù)定成功,開始選乘坐人')
break
else:
print('---正在查詢你所需要的車次---',end='\r') #覆蓋前面一句---正在查詢你所需要的車次---,不然每循環(huán)一次,就會打印一次這句話
return order_ticket_message
finally_message=order_ticket()
if finally_message=='---本次搶票已結(jié)束,祝你好運(yùn)---':
print('---即將關(guān)閉瀏覽器打開的所有窗口---')
driver.quit()
time.sleep(1)
print('---瀏覽器已關(guān)閉---')
else:
time.sleep(2)
# 點(diǎn)擊乘車人信息,默認(rèn)第一個為本人
driver.find_element_by_xpath('//*[@id="normalPassenger_0"]').click()
time.sleep(1)
print('---乘車人選擇成功,默認(rèn)選擇12306上面乘車人列表的第一位---')
time.sleep(1)
#點(diǎn)擊提交訂單
driver.find_element_by_xpath('//*[@id="submitOrder_id"]').click()
time.sleep(1)
print('---已提交訂單---')
time.sleep(1)
#下面可能存在邏輯錯誤
#選座
print('---窗戶 A B C 過道 D F窗戶---')
time.sleep(1)
seat=input('---輸入你想要的位置,如果沒有該位置,隨機(jī)為你選擇一個位置---\n---輸入格式:place_X---\n---X為A B C D F---\n')
time.sleep(1)
seat_A='//*[@id="1A"]' #座位
seat_B='//*[@id="1B"]'
seat_C='//*[@id="1C"]'
seat_D='//*[@id="1D"]'
seat_F='//*[@id="1F"]'
decision_true='//*[@id="qr_submit_id"]' #確定
pay_money='---沒有自己想要選擇的位置了,隨機(jī)!---'
try:
seat=='place_A'
driver.find_element_by_xpath(seat_A).click()
time.sleep(1)
driver.find_element_by_xpath(decision_true).click()
pay_money = '---選座成功!寶貝,快來付錢---'
print('---選座成功!寶貝,快來付錢---')
time.sleep(1)
seat = 'place_A'
except:
driver.find_element_by_xpath(seat_A).click()
time.sleep(1)
print('你選的不是位置A/沒有位置A了')
time.sleep(1)
try:
seat == 'place_B'
driver.find_element_by_xpath(seat_B).click()
time.sleep(1)
driver.find_element_by_xpath(decision_true).click()
pay_money = '---選座成功!寶貝,快來付錢---'
print('---選座成功!寶貝,快來付錢---')
time.sleep(1)
seat = 'place_B'
except:
time.sleep(1)
print('你選的不是位置B/沒有位置B了')
time.sleep(1)
try:
seat=='place_C'
driver.find_element_by_xpath(seat_C).click()
time.sleep(1)
driver.find_element_by_xpath(decision_true).click()
pay_money = '---選座成功!寶貝,快來付錢---'
print('---選座成功!寶貝,快來付錢---')
time.sleep(1)
seat = 'place_C'
except:
time.sleep(1)
print('你選的不是位置C/沒有位置C了')
time.sleep(1)
try:
seat=='place_D'
driver.find_element_by_xpath(seat_D).click()
time.sleep(1)
driver.find_element_by_xpath(decision_true).click()
pay_money = '---選座成功!寶貝,快來付錢---'
print('---選座成功!寶貝,快來付錢---')
time.sleep(1)
seat = 'place_D'
except:
time.sleep(1)
print('你選的不是位置D/沒有位置D了')
time.sleep(1)
try:
seat=='place_F'
driver.find_element_by_xpath(seat_F).click()
time.sleep(1)
driver.find_element_by_xpath(decision_true).click()
pay_money = '---選座成功!寶貝,快來付錢---'
print('---選座成功!寶貝,快來付錢---')
time.sleep(1)
seat = 'place_F'
except:
time.sleep(1)
print('你選的不是位置F/沒有位置F了')
time.sleep(1)
if pay_money !='---選座成功!寶貝,快來付錢---':
print(pay_money)
driver.find_element_by_xpath(decision_true).click()
time.sleep(1)
print('15分鐘內(nèi),快去掃碼付錢!')
else:
print('15分鐘內(nèi),快去掃碼付錢!')
pay_result=input('---付款是否成功,選擇是或否---')
if pay_result=='是':
driver.quit()
else:
print('---selenium不穩(wěn)定---')
新人創(chuàng)作不易,覺得不錯的看官,點(diǎn)個贊吧,么么噠!??!文章來源:http://www.zghlxwxcb.cn/news/detail-601952.html
該篇僅用來學(xué)習(xí),禁止轉(zhuǎn)載!文章來源地址http://www.zghlxwxcb.cn/news/detail-601952.html
到了這里,關(guān)于【selenium12306搶票購票腳本】肝了一周,2萬3千字超詳細(xì)代碼詳解 【建議收藏】的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!