Python实现12306自动抢火车票功能


目录
  • 一、效果展示
  • 二、代码详解
    • 1 导入库
    • 2 确定好购票基本信息
    • 3 登录12306
    • 4 模拟滑动滑块
    • 5 处理疫情特殊要求
    • 6 点击购票并填写出发地、目的地、出发时间
    • 7 锁定车票

大家有没有这种感觉,一到国庆、春节这种长假,抢火车票就非常困难?各大互联网公司都推出抢票服务,只要加钱给服务费就可以增加抢到票的几率。有些火车票代售网点和一些加速买票软件,说你只要给100元服务费就可以优先帮忙抢到票。本文和你一起探索抢票软件背后的原理。

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不定期会更新买票界面,所以过一段时间可能之前的代码就要进行一些调整,需要自己弄清里面的原理,才可以以不变应万变。本文的代码没有进行高级的封装,只为大家能更清楚地了解每一步,能在抢票高峰期买到自己心仪的票。

也写得很基础,没有进一步的调优缩短时效,感兴趣的朋友可以自行研究,如有任何疑问可以跟我沟通。