目录
一、说明
1.1、背景
1.2、说明
二、步骤
2.1、切换视角检索乘车乘客
2.2、选择乘客
2.3、关闭学生票选择界面
2.4、提交订单
2.5、选择座位并确认
三、完整代码与视频演示
3.1、完整源代码如下
3.2、视频演示代码运行
四、结果
4.1、代码运行结果
五、总结与完善
5.1、总结
5.2、完善
一、说明
1.1、背景
接前面一、二部分解决抢不到票的问题,本部分解决乘客选择与车票提交问题,并完整完成自动化购票功能。
1.2、说明
操作系统:win 10
编辑器:pycharm edu
语言及版本:python 3.10
使用的库:selenium
实现思路:使用selenium模拟人的行为,进行自动化操作
关于代码:完整代码已放出
第一部分内容-->已解决登录问题
第一部分内容链接:第一部分内容
第二部分内容-->已解决车次查找与预定车次问题
第二部分内容链接:第二部分内容
浏览器下载与驱动的安装:火狐浏览器下载与驱动下载
浏览器闪退说明:大概率是因为下载的浏览器和浏览器驱动版本不一致,建议使用搜索引擎查找大佬分享的内容解决
tips:以下url不会放真实的,拿来测试注意识别并自行更改。
二、步骤
当前界面默认进入乘客选择界面,因为之前的内容已经进入到该界面了。
2.1、切换视角检索乘车乘客
需要先把这个提示内容去掉,在输入需要购买车票的乘客名字进行检索,如下图1;
# 进入订单界面,切换视角
driver.switch_to.window(driver.window_handles[-1])
time.sleep(3) # 给加载时间
# 进入乘客选择
driver.find_element(By.XPATH, '//*[@id="quickQueryPassenger_id"]').click() # 先点击,把提示内容去除
driver.find_element(By.XPATH, '//*[@id="quickQueryPassenger_id"]').send_keys("乘客名字") # 输入乘客姓名
图1
2.2、选择乘客
乘客检索出来后,进行乘客的选择,如下图2;
time.sleep(0.5) # 给加载时间
driver.find_element(By.XPATH, '//*[@id="normalPassenger_0"]').click() # 选择乘客
图2
2.3、关闭学生票选择界面
选择乘客后,如果是学生会出现学生票购买提示页面,需要关闭这个页面,如下图3;
time.sleep(2) # 给加载时间
driver.find_element(By.XPATH, '//*[@id="dialog_xsertcj_cancel"]').click() # 关闭学生票选项
图3
2.4、提交订单
一切准备就绪,可以进行提交订单了,如下图4;
driver.find_element(By.XPATH, '//*[@id="submitOrder_id"]').click() # 提交订单
图4
2.5、选择座位并确认
座位选择的是F靠窗位置,座位不选择直接提交订单,随机座位也是可以的;
# 选择座位,这里选择的是靠窗的F座位,不选择座位也是可以的
driver.find_element(By.XPATH, '//*[@id="1F"]').click()
# 点击确认订单
driver.find_element(By.XPATH, '//*[@id="qr_submit_id"]').click()
三、完整代码与视频演示
3.1、完整源代码如下
from selenium.webdriver import Firefox # 导入火狐
from selenium.webdriver.common.action_chains import ActionChains # 导入时间链
from selenium.webdriver.common.by import By # 导入需要的组件
from selenium.webdriver.common.keys import Keys
import time
def login_shop():
login_url = "这里是12306登录的url" # 登录界面url
trains = ['G4362', 'K1208'] # 这里是你要购买票的车次名称
driver = Firefox()
driver.get(login_url)
script = 'Object.defineProperty(navigator,"webdriver",{get:()=>false,});'
driver.execute_script(script)
driver.find_element(By.XPATH, '//*[@id="J-userName"]').send_keys("你的账户")
driver.find_element(By.XPATH, '//*[@id="J-password"]').send_keys("你的密码")
driver.find_element(By.XPATH, '//*[@id="J-login"]').click()
time.sleep(5)
push_btu = driver.find_element(By.XPATH, '//*[@id="nc_1_n1z"]')
# 拖动滑块后,会跳转新窗口 //*[@id="nc_1_n1z"]
ActionChains(driver).drag_and_drop_by_offset(push_btu, 300, 0).perform()
# 切换到新窗口
driver.switch_to.window(driver.window_handles[-1])
time.sleep(3)
# 刷新
driver.refresh()
time.sleep(3)
# 在新窗口点击前往订票,又会跳转到新窗口
driver.find_element(By.XPATH, '//*[@id="link_for_ticket"]').click()
# 这里也生成了一个新窗口,需要切换
driver.switch_to.window(driver.window_handles[-1])
time.sleep(5)
# 出发地
driver.find_element(By.XPATH, '//*[@id="fromStationText"]').click()
driver.find_element(By.XPATH, '//*[@id="fromStationText"]').send_keys("深圳北", Keys.ENTER)
# 目的地
driver.find_element(By.XPATH, '//*[@id="toStationText"]').click()
driver.find_element(By.XPATH, '//*[@id="toStationText"]').send_keys("百色", Keys.ENTER)
# 日期,先清除默认内容,在输入
driver.find_element(By.XPATH, '//*[@id="train_date"]').click()
driver.find_element(By.XPATH, '//*[@id="train_date"]').clear()
driver.find_element(By.XPATH, '//*[@id="train_date"]').send_keys("2023-01-20")
# 点击查询
driver.find_element(By.XPATH, '//*[@id="query_ticket"]').click()
# 保存加载出来的车次信息,并进行筛选判断
time.sleep(6) # 确保页面内容加载完成
# print(driver.current_url)
tr_list = driver.find_elements(By.XPATH, ".//tbody[@id='queryLeftTable']/tr[not(@datatran)]")
# //*[@id="queryLeftTable"]
for tr in tr_list: # 遍历所有车次信息
train_number = tr.find_element(By.CLASS_NAME, "number").text # 车次
print(train_number)
if train_number in trains: # 如果该车次在输入的车次里
left_ticker_td = tr.find_element(By.XPATH, './/td[4]').text
if left_ticker_td == '有' or left_ticker_td.isdigit(): # 如果该车次有票
print(train_number+'有票')
btn72 = tr.find_element(By.CLASS_NAME, 'btn72') # 找到该车次的预订按钮
btn72.click()
break # 这里点击了之后一定要退出,否则程序继续循环会导致报错
# 进入订单界面,切换视角
driver.switch_to.window(driver.window_handles[-1])
time.sleep(3) # 给加载时间
# 进入乘客选择
driver.find_element(By.XPATH, '//*[@id="quickQueryPassenger_id"]').click() # 先点击,把提示内容去除
driver.find_element(By.XPATH, '//*[@id="quickQueryPassenger_id"]').send_keys("乘客名称") # 输入乘客姓名
time.sleep(0.5) # 给加载时间
driver.find_element(By.XPATH, '//*[@id="normalPassenger_0"]').click() # 选择乘客
time.sleep(2) # 给加载时间
driver.find_element(By.XPATH, '//*[@id="dialog_xsertcj_cancel"]').click() # 关闭学生票选项
driver.find_element(By.XPATH, '//*[@id="submitOrder_id"]').click() # 提交订单
# 选择座位,这里选择的是靠窗的F座位,不选择座位也是可以的
driver.find_element(By.XPATH, '//*[@id="1F"]').click()
# 点击确认订单
driver.find_element(By.XPATH, '//*[@id="qr_submit_id"]').click()
if __name__ == '__main__':
login_shop()
3.2、视频演示代码运行
视频已经制作好了,但是有些奇怪不知道为啥电脑接收不了,所以就不上传了,需要视频请在评论区评论或者私聊我。
四、结果
4.1、代码运行结果
如下图5:
图5
五、总结与完善
5.1、总结
1)将一个大问题分析若干部分解决,将会变得轻松;
2)多学习;
5.2、完善
1)在以上的代码中用到了很多延时来确保页面可以加载成功,导致抢票慢,那么如何改进呢?
有两个库可以解决这个问题;
from selenium.webdriver.support.ui import WebDriverWait # 条件等待 from selenium.webdriver.support import expected_conditions # 导入判断条件
加入限定条件,确保页面加载完成了在进行下一步代码的执行,就不需要一直time.sleep了;
2)我们简陋的程序如何能抢得过各大抢票平台呢?
使用服务器进行代码的持续运行,增加购票成功的几率;
3)我们代码只能进行单次的抢票,如何进行多次抢票呢?
使用循环,或者其它条件,指定时间就执行一次代码,进行查票购票等操作即可;
4)买到票之后,只有10分钟的付款时间,抢到票如何进行快速通知呢?
Python实现用QQ邮箱发邮件进行提醒等;
总之,购票平台的自动化购票对我而言是一次很好的锻炼,以上内容是粗略记录该过程,之后更加完善自动化购票功能在进行分享,欢迎批评指正;