大家好,我是好学的小师弟,由于没抢到中秋回家的票,所以我写了这个脚本,还有些模块没有完善,后期会补上。写这个主要是用来加强自己对selenium和python的学习理解。该脚本仅供大家学习参考,辅助大家理解selenium知识。
目录
一、铁路12306登录
1.反爬虫
2.滑块验证码问题解决
3.登录模块完整代码
二、出发地,目的地,乘车日期的选择
1.乘车日期、出发地、目的地代码思路和遇到的问题
2.乘车日期、出发地、目的地模块代码
三、购票、抢票模块
1.流程概述
2.目前程序存在的缺点
3.程序难点(对我个人而言)
4.抢票、购票模块代码
四、选座模块
五、其他
1.查询余票页面,显示页面超时
2.pycharm与界面的切换
六、完整代码
2021.9.24 更新
一、铁路12306登录
首先我们打开12306的页面,中国铁路12306。发现页面是需要二维码登陆的,所以我们要在代码里,先去选择点击账号密码登录。
1.反爬虫
这里如果你直接输入账号密码,是不会显示出验证码来的,直接给你报错。输入以下代码即可解决问题
script = 'Object.defineProperty(navigator,"webdriver",{get:()=>undefined,});'
driver.execute_script(script)
在代码里输入账号和密码后,会出现验证码。这里的验证码是滑块验证码,所以我们可以通过selenium的鼠标事件来执行。
from selenium.webdriver import ActionChains #导入鼠标事件
2.滑块验证码问题解决
思路: 先确定滑块的初始位置元素,选中它,然后模拟鼠标按住不放,向右平移拖动一定的距离,即可完成验证。验证后,释放鼠标,不然后面鼠标就用不了了(一直会处在这个命令执行状态中)。记得perform()执行,这个指令不能忘
代码:
#滑动验证码
#定位验证码的头位置元素
time.sleep(1)
picture_start=driver.find_element_by_id('nc_1_n1z')
#移动到相应的位置,并左键鼠标按住往右边拖
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 #导入鼠标事件
from selenium.webdriver.common.keys import Keys #键盘功能键封装的一个函数
driver=webdriver.Chrome() #驱动
url='https://kyfw.12306.cn/otn/resources/login.html' #铁路12306网址
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()#点击账号密码登录
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()
#滑动验证码
#定位验证码的头位置元素
time.sleep(1)
picture_start=driver.find_element_by_id('nc_1_n1z')
#移动到相应的位置,并左键鼠标按住往右边拖
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('---程序正在运行---')
driver.find_element_by_xpath('//*[@id="J-index"]/a').click()
#最小化窗口
driver.minimize_window()
time.sleep(1)
二、出发地,目的地,乘车日期的选择
1.乘车日期、出发地、目的地代码思路和遇到的问题
登陆成功后,我们就来到了出发地,目的地和乘车日期的选择界面。这里我们用到了selenium的封装keys函数,keys函数可以用来调用键盘上的一些功能键,比如control,enter,backspace等。通过keys函数我们就可以做到把输入文本框里的内容,全选+删除,然后输入我们想要的出发日期,目的地,出发地。
注意:这里的出发日期是含有下拉框的,你输入你想要的日期之后,下拉框还是不会消失,下拉框不消失,他就会覆盖到你的查询按钮,从而导致你click不到查询这个元素,无法完成接下来的操作,程序会报错。这个时候你点击空白处,下拉框才会消失,但是selenium中我没定位到空白区域的元素(或者就是压根没有?怀疑中),所以我找了另一个方法,点击静态图片,因为他们没有超链接,也就相当于空白区域,从而达到使得下拉框消失的目的,让程序可以接着运行。
2.乘车日期、出发地、目的地模块代码
here_place=input('---你的出发地---\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)
#买哪天的票,出发日期填写
travel_date=input('由于疫情目前12306只支持提前15天买票\n出发日期格式: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:
#不能一次性点到链接,那就中间再点两次无用的静态文字
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)
# 点击页面上的静态图片(没有内含超链接),为了把上面车票的日期下拉框给去掉
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)
#点击页面上的静态图片(没有内含超链接),为了把上面车票的日期下拉框给去掉
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点或者下午5点(时间有可能有变化,看情况)。所以,我们只需要在程序中加一个定时模块就OK了,提前3分钟执行程序,就完成了抢票功能。
来说说购票
思路:点击查询按钮,先询问购票人是否需要购买学生票,然后输入你想要乘坐的车次,这里我预选的是二等座,如果你想要乘坐硬座,列表[]里写入15,我记得好象是,你可以把返回的字符串列表,打印出来,然后一个个数,看硬座所对应的位置是列表[]多少,然后改一下就行了。
查询余票会出现两种情况:
1.如果有余票,直接帮你预定,程序跳到下一步选座模块。
2.没有余票了或者票还没发售,程序开始不停的点击查询按钮,一旦发售或者有票,立刻帮你预定上(这里我好像只设置了运行30秒,我觉得30秒没抢到票,基本也没戏了。。。>-<)抢到票,就跳到选座模块;抢不到,浏览器直接退出。
2.目前程序存在的缺点
如果12306的页面搜索出现两行同名称的列车车次,并且你想乘坐这辆车,他只会选中第一辆车
目前只支持购买一个人的票,并且是乘车人列表出现的第一个人
3.程序难点(对我个人而言)
1.xpath的元素定位
/ 绝对定位
//相对定位
. 当前节点
.//a[@id='苏州'] 当前节点的相对位置下 a标签中的属性为id的,且id的值为苏州的xpath路径
通过这种纯手写的xpath路径方法,可以更快的获得我们想要的元素
如果我们f12,点击元素,右键copy中选择xpath,往往得到的是含有通配符的//*[@id='苏州'],这种方法,往往只能获取到一个元素,但我们想要爬的是一个列表,所以这种方法在这个时候,就不是那么合适。
2.字符串如何变成列表?
我们爬下来的所乘日期当天的班次是字符串,所以我们需要把字符串变为列表。不然的话,不好定位,不好写输出哪个值
两种方法
第一种 分-总形式
自己定义一个空列表,然后for in 遍历;空列表进行追加,把车次,二等座,硬座,余票等等这些全部挨个建列表,然后再通过一个for in遍历找到你所想要的那个车次,看循环第几遍找到,然后列表输出那个数字-1,这样子就找到了,我们想要的信息了
第二种方法 总—split函数—>字符串列表
直接把当天的班次,全部打印出来,找共同点,通过split函数对他们进行切片,分割。split返回的即是字符串列表。这个更方便一点
3.逻辑思考
这里就是if else try except 这些逻辑上的编写, 还有break的循环跳出 ,还有就是自定义函数的编写调用。这点就是要考虑的场景太多了,耗时间和逻辑太多。。。所以我直接把场景设置死了,但是还是会有很多可能性。。。
4.抢票、购票模块代码
#看乘车人是否为学生,是否想购买学生票
def student():
stu=input('是否购买学生票,请输入是或否\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='已勾选购买学生票'
return accept_stu
student()
time.sleep(1)
#还没开始售票,在不断点击预定按钮
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('---您选的车次二等座有票了,正在为您预定---')
time.sleep(0.5)
button = train_number.find_element_by_xpath('.//a[@class="btn72"]') # 已经锁定车次,对当前车次进行车票预定
time.sleep(0.5)
button.click()
# .//a[@class="btn72"]意思就是取a标签的属性为class的值为btn72的元素xpath
time.sleep(1)
success_message='---预定成功,现在正在选择乘车人---'
print('---预定成功,现在正在选择乘车人---')
break
else:
print('继续点击查询按钮,刷新余票',end='\r')
else:
time.sleep(1)
success_message='---查询时间已到!抱歉,您所选的车次,目前没有二等座的票了,您可去12306官网,继续查询---'
time.sleep(0.5)
print('---查询时间已到!抱歉,您所选的车次,目前没有二等座的票了,您可去12306官网,继续查询---')
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,因为有好多个元素,这里定位的是不含datatran的所有元素
for train_number in train_numbers:
order_ticket_message=''
train_messages=train_number.text.replace('\n',' ')#把换行符替换成空格
train_message=train_messages.split(' ')
'''
split():拆分字符串。通过指定分隔符对字符串进行切片,并返回分割后的字符串列表(list)
'''
if train_num==train_message[0]:
print('---找到你想要的车次了---')
if'有'==train_message[10]or'有'==train_message[9]:#这里的列表数值,各个车可能有出入,到时候大家打印下整个车次列表,然后再改下数字就行了
print('---该车次现在有二等座---')
time.sleep(1)
button=train_number.find_element_by_xpath('.//a[@class="btn72"]')#已经锁定车次,对当前车次进行车票预定
button.click()
#.//a[@class="btn72"]意思就是取a标签的属性为class的值为btn72的元素xpath
time.sleep(1)
order_ticket_message='预定成功,现在正在选择乘车人'
print('预定成功,现在正在选择乘车人')
break
else:
print('---抱歉,您所选的车次车票,目前没票了,存在有候补票这种情况,正在为你刷新页面,实时更新车票情况---')
result='---查询时间已到!抱歉,您所选的车次,目前没有二等座的票了,您可去12306官网,继续查询---'
time.sleep(1)
success_messages=refresh_search_ticket(train_message,train_number)
if result==success_messages:
time.sleep(1)
order_ticket_message='---本次抢票已结束,祝你好运---'
print('---本次抢票已结束,祝你好运---')
break
else:
order_ticket_message='查到票了,预定成功,开始选乘坐人'
print('查到票了,预定成功,开始选乘坐人')
break
else:
print('---正在查询你所需要的车次---',end='\r') #覆盖前面一句---正在查询你所需要的车次---,不然每循环一次,就会打印一次这句话
return order_ticket_message
finally_message=order_ticket()
if finally_message=='---本次抢票已结束,祝你好运---':
print('---即将关闭浏览器打开的所有窗口---')
driver.quit()
time.sleep(1)
print('---浏览器已关闭---')
else:
time.sleep(2)
# 点击乘车人信息,默认第一个为本人
driver.find_element_by_xpath('//*[@id="normalPassenger_0"]').click()
print('---乘车人选择成功,默认选择12306上面乘车人列表的第一位---')
time.sleep(0.5)
点击提交订单
driver.find_element_by_xpath('//*[@id="submitOrder_id"]').click()
四、选座模块
因为12306每天只有3次机会退票,好象是。所以我没法多测试这个模块到底行不行。。。。
#选座,报错预警>_< 。。。可能会涉及到网络超时问题
print('---窗户 A B C 过道 D F窗户---')
time.sleep(1)
seat=input('---输入你想要的位置,如果没有该位置,随机为你选择一个位置---\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='---没有自己想要选择的位置了,随机!---'
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分钟内,快去扫码付钱!')
else:
print('15分钟内,快去扫码付钱!')
pay_result=input('---付款是否成功,选择是或否---')
if pay_result=='是':
driver.quit()
else:
print('---selenium不稳定---')
五、其他
1.查询余票页面,显示页面超时
晚上10点后,12306pc网页就不太行了,一直显示超时,所以我们就尽量不要在这个时候去登陆,我也写了一个刷新函数,有效果,虽然解决了这个页面超时问题,但是选座的时候,还会出现新的网络超时问题。。。。
2.pycharm与界面的切换
在pycharm下方出现 '等待中' 以后的那个查询余票界面,要切出来到pycharm中继续写你的需求,这个切换,最好用tab+alt。
六、完整代码
from selenium import webdriver
import time
from selenium.webdriver import ActionChains #导入鼠标事件
from selenium.webdriver.common.keys import Keys #键盘功能键封装的一个函数
'''
by csdn 好学的小师弟
博客:https://blog.csdn.net/weixin_43784564
新人小白,欢迎大家一起学习,交流,互相进步
注:本文目前还差一个定时执行任务脚本,且目前只支持选择含有二等座选项的车次,购买的也是二等座。
如果12306的页面搜索出现两行同名称的列车车次,这个程序就会报错
目前只支持购买一个人的票
目前只测出这些bug,还有好多种乘车情况没考虑,因为逻辑太多了,写不来了,白天要打工 >_<
如果想要自动执行,就把input写死,然后加个定时执行脚本就行了
注意:12306网页晚上10点左右好像就不灵光了,打开有困难,一直显示页面超时
页面和pycharm之间切换,用tab+alt
如果报错,要么就是网络问题、又要你重新登陆了,多试几次
要么就是selenium不稳定。
要么就是我写的程序有问题,逻辑出错。可惜我没时间去测试改了
(主要是选座的那一块,我发博客之前零食写的,没时间了,tfs一堆任务要去忙)
白天打工太累了。。。。。
如果这个脚本对大家学习selenium和python有帮助的话,大家可以写一个完善版
如果程序一直报错,那就把选座模块注释掉,再运行;
我昨晚试了下没有选座模块的程序,是能正常运行的。
选座模块是我今天中午吃饭的时候写的,还没来得及测试。
本脚本,仅用来让大家互相交流学习,大家一起共同进步!
'''
driver=webdriver.Chrome() #驱动
url='https://kyfw.12306.cn/otn/resources/login.html' #铁路12306网址
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()#点击账号密码登录
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()
#滑动验证码
#定位验证码的头位置元素
time.sleep(1)
picture_start=driver.find_element_by_id('nc_1_n1z')
#移动到相应的位置,并左键鼠标按住往右边拖
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('---程序正在运行---')
driver.find_element_by_xpath('//*[@id="J-index"]/a').click()
#最小化窗口
driver.minimize_window()
time.sleep(1)
here_place=input('---你的出发地---\n')
driver.find_element_by_xpath('//*[@id="fromStationText"]').clear() #清除对话框原内容,这里用的是clear函数
driver.find_element_by_xpath('//*[@id="fromStationText"]').send_keys(here_place)#输入你的出发地
time.sleep(0.5)
#因为12306输入出发地存在一个下拉框问题,所以这里我们使用keys这个封装好的函数,来调用键盘上的回车键,这样就避免了鼠标点击空白处 这个操作
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)
#买哪天的票,出发日期填写
travel_date=input('由于疫情目前12306只支持提前15天买票\n出发日期格式:20xx-05-07\n')
time.sleep(1)
#这里用的是keys函数,调用ctrl+a全选,然后按删除键,删除原对话框内容
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)
'''
这里注意,就算你输入了订票日期,下拉框也依旧存在,这里我们使用以下方法,解决这个问题,详细解释
https://blog.csdn.net/weixin_43784564/article/details/120352680
'''
try:
#不能一次性到链接,那就中间再点两次无用的静态文字
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)
# 点击页面上的静态图片(没有内含超链接),为了把上面车票的日期下拉框给去掉
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)
#点击页面上的静态图片(没有内含超链接),为了把上面车票的日期下拉框给去掉
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)
'''
为什么要获得窗口句柄,详细解释详见我上一条csdn博客https://blog.csdn.net/weixin_43784564/article/details/120368372
'''
# 获取打开的多个窗口句柄
windows = driver.window_handles
# 切换到当前最新打开的窗口
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('---这个温馨提示我没叉掉/不存在温馨提示---')
#现在来到了购票页面,点击查询按钮
#这里出现一个问题,会出现页面查询超时,所以我们应该搞个功能,即点击按钮,直到出现车次情况!!!用到自己写的一个函数
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)
#如果页面查询超时,就用下面这个函数
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('---正在点击查询按钮---',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)
#看乘车人是否为学生,是否想购买学生票
def student():
stu=input('是否购买学生票,请输入是或否\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='已勾选购买学生票'
return accept_stu
student()
time.sleep(1)
#注意,本抢票脚本只适用于开始售票的那几分钟有用,毕竟抢票就抢那几分钟
#注意,本抢票脚本还差一个定时执行任务脚本。需要你定个时
#定义一个函数,如果发现目前页面没票了,就不断刷新页面,给你查询是否有票现在.
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('---您选的车次二等座有票了,正在为您预定---')
time.sleep(0.5)
button = train_number.find_element_by_xpath('.//a[@class="btn72"]') # 已经锁定车次,对当前车次进行车票预定
time.sleep(0.5)
button.click()
# .//a[@class="btn72"]意思就是取a标签的属性为class的值为btn72的元素xpath
time.sleep(1)
success_message='---预定成功,现在正在选择乘车人---'
print('---预定成功,现在正在选择乘车人---')
break
else:
print('继续点击查询按钮,刷新余票',end='\r')
else:
time.sleep(1)
success_message='---查询时间已到!抱歉,您所选的车次,目前没有二等座的票了,您可去12306官网,继续查询---'
time.sleep(0.5)
print('---查询时间已到!抱歉,您所选的车次,目前没有二等座的票了,您可去12306官网,继续查询---')
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,因为有好多个元素,这里定位的是不含datatran的所有元素
for train_number in train_numbers:
order_ticket_message=''
train_messages=train_number.text.replace('\n',' ')#把换行符替换成空格
train_message=train_messages.split(' ') #split切割函数,用' '来切片,并返回字符串列表
if train_num==train_message[0]:
print('---找到你想要的车次了---')
if'有'==train_message[10]or'有'==train_message[9]:#这里的列表数值,各个车可能有出入,到时候大家打印下整个车次列表,然后再改下数字就行了,一般来说是不用改的
print('---该车次现在有二等座---')
time.sleep(1)
button=train_number.find_element_by_xpath('.//a[@class="btn72"]')#已经锁定车次,对当前车次进行车票预定
button.click()
#.//a[@class="btn72"]意思就是取当前节点,相对路径下的a标签的属性为class的值为btn72的元素xpath
time.sleep(1)
order_ticket_message='预定成功,现在正在选择乘车人'
print('预定成功,现在正在选择乘车人')
break
else:
print('---抱歉,您所选的车次车票,目前没票了,存在有候补票这种情况,正在为你刷新页面,实时更新车票情况---')
result='---查询时间已到!抱歉,您所选的车次,目前没有二等座的票了,您可去12306官网,继续查询---'
time.sleep(1)
#没票了,现在调用不断刷新页面的函数,来给你查询余票,并返回值
success_messages=refresh_search_ticket(train_message,train_number)
if result==success_messages:
time.sleep(1)
order_ticket_message='---本次抢票已结束,祝你好运---'
print('---本次抢票已结束,祝你好运---')
break
else:
order_ticket_message='查到票了,预定成功,开始选乘坐人'
print('查到票了,预定成功,开始选乘坐人')
break
else:
print('---正在查询你所需要的车次---',end='\r') #覆盖前面一句---正在查询你所需要的车次---,不然每循环一次,就会打印一次这句话
return order_ticket_message
finally_message=order_ticket()
if finally_message=='---本次抢票已结束,祝你好运---':
print('---即将关闭浏览器打开的所有窗口---')
driver.quit()
time.sleep(1)
print('---浏览器已关闭---')
else:
time.sleep(2)
# 点击乘车人信息,默认第一个为本人
driver.find_element_by_xpath('//*[@id="normalPassenger_0"]').click()
time.sleep(1)
print('---乘车人选择成功,默认选择12306上面乘车人列表的第一位---')
time.sleep(1)
#点击提交订单
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('---输入你想要的位置,如果没有该位置,随机为你选择一个位置---\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='---没有自己想要选择的位置了,随机!---'
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分钟内,快去扫码付钱!')
else:
print('15分钟内,快去扫码付钱!')
pay_result=input('---付款是否成功,选择是或否---')
if pay_result=='是':
driver.quit()
else:
print('---selenium不稳定---')
新人创作不易,觉得不错的看官,点个赞吧,么么哒!!!文章来源:https://www.toymoban.com/news/detail-601952.html
该篇仅用来学习,禁止转载!文章来源地址https://www.toymoban.com/news/detail-601952.html
到了这里,关于【selenium12306抢票购票脚本】肝了一周,2万3千字超详细代码详解 【建议收藏】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!