首页 > Python基础教程 >
-
Python实现12306自动抢火车票功能
大家有没有这种感觉,一到国庆、春节这种长假,抢火车票就非常困难?各大互联网公司都推出抢票服务,只要加钱给服务费就可以增加抢到票的几率。有些火车票代售网点和一些加速买票软件,说你只要给100元服务费就可以优先帮忙抢到票。本文和你一起探索抢票软件背后的原理。
一、效果展示
很多人学习蟒蛇,不知道从何学起。 很多人学习寻找python,掌握了基本语法之后,不知道在哪里案例上手。 很多已经可能知道案例的人,却不怎么去学习更多高深的知识。 这三类人,我给大家提供一个好的学习平台,免费获取视频教程,电子书,以及课程的源代码! QQ群:101677771 欢迎加入,一起讨论学习
在正式进入代码讲解之前,先来看下本文的实现效果。
如果不是为了演示效果,直接在最后确定阶段加一个延时点击确定,应该不到45秒可以锁定一张票,只要在30分钟之内付款即可。
二、代码详解
本小节会详细解锁抢票软件是如何模拟登录网站,进行自动买票的。为了更清晰地给大家展示,部分代码没有写成函数,直接裸代码运行,让需要买票的朋友可以自己应用软件进行购票。
1 导入库
首先导入本文需要加载的库,如果你有些库还没有安装,导致运行代码时报错,可以在Anaconda Prompt中用pip方法安装。
1
2
3
4
5
6
7
8
9
10
11
|
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代码中填写你购票的基本信息。
1
2
3
4
5
6
7
8
9
|
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了,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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登录网址:
https://kyfw.12306.cn/otn/resources/login.html
接着点击账户密码登录,会出现如下界面:
然后点击红框中的三个点,找到更多工具,点击开发者工具,会出现如下界面:
点击红框中的箭头,把鼠标移动到账户框上去,就会出现如下界面:
右边变灰的框里就会出现对应的id,点击账号框,再把鼠标移动到右边变灰的字符上去,点击右键,会出现copy element的选项,复制下来即可。
1
|
< 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 模拟滑动滑块
输入完用户名和密码,点击立即登录后,会出现如下滑块验证要求。
运行如下代码即可拖动滑块进行验证。
1
2
3
4
5
6
7
8
9
10
|
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 处理疫情特殊要求
完成滑块验证要求后,会出现如下疫情特殊要求提示:
用如下代码点击确认即可。
1
2
3
4
|
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 点击购票并填写出发地、目的地、出发时间
接下来是选择买票,并将出发地、目的地、出发时间等信息填写进去。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
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中的车次是否有票,有的话点击购买锁定车票。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
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不定期会更新买票界面,所以过一段时间可能之前的代码就要进行一些调整,需要自己弄清里面的原理,才可以以不变应万变。本文的代码没有进行高级的封装,只为大家能更清楚地了解每一步,能在抢票高峰期买到自己心仪的票。
也写得很基础,没有进一步的调优缩短时效,感兴趣的朋友可以自行研究,如有任何疑问可以跟我沟通。
出处:https://www.cnblogs.com/sn5200/p/15830033.html