大学生、旅游救星来了,12306自动实现准时准点抢票。python实现抢票(超详细版)

前言

每逢佳节或者说走就走的旅行,就如同蜿蜒的山路充满了各种障碍。当我们确定行程的目的地,当期待着一场充满激情旅行,也或许思念亲人。但却在抢票的激烈战斗中屡屡碰壁时眼前却显出四个大字:“票已售磬”。不得不将所有的念想打消,虽然道路上可能会有重重障碍,但本次我将为大家跨越第一道大门。(ps:前言可跳过)

一、安装驱动

1.1、selenium库

因为本次为网页版抢购,所以我们将安装selenium库实现获取屏幕上面的重要参数。这里采用清华镜像网站直接安装。

pip install selenium -i  https://pypi.tuna.tsinghua.edu.cn/simple 

1.2、驱动文件

目前对于网页的大部分处理方法都是通过驱动文件,进行实现的。如果未安装谷歌浏览器请先安装谷歌浏览器(下载链接)。在下载驱动文件之前需要先查看谷歌对应版本,方法如下。

这里我们可以清楚看到对应谷歌的版本,那么下面就可以安装驱动文件了。然后对应的版本号进行下载,如果没找到对应的版本号,那么需要一个比较近的下载即可。假如你的版本号为103.0.5060.44,那么应该下载对应版本103.0.5060.53。(尽量把浏览器更新到近几月的版本,这样更全面。) 

下载完成是一个压缩包,将压缩包解压后是一个.exe文件,将文件放进谷歌浏览器文件中即可,大家可以跟我放相同的文件中,如图所示。

我们到目前为止,所有准备工作就做完了(如上面步骤你已经之前操作过,那么直接看第二步)。下面将放代码部分。

二、代码部分

2.1、导入所需库

import pandas as pd
import csv
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException, ElementNotVisibleException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

2.2、目的地网站地址

这里我们可以精确到网站的目的地,明确目标。

class train(object):
    # 登录界面的url
    login_url = "https://kyfw.12306.cn/otn/resources/login.html"
    # 个人界面的url
    personal_url = "https://kyfw.12306.cn/otn/view/index.html"
    # 选择地点时间界面的url
    left_tickets = "https://kyfw.12306.cn/otn/leftTicket/init?"
    # 提交订单界面的url
    confirm_url = "https://kyfw.12306.cn/otn/confirmPassenger/initDc"

2.3、处理信息

对于本次目的地已经确认,进行对应的处理。

    def __init__(self, from_station, to_station, time_data, train_number, name):
        self.from_station = from_station
        self.to_station = to_station
        self.time_data = time_data
        self.train_number = train_number
        self.name = name
        self.select_number = None

        # 初始化站点所对应的代号
        self.station_codes = {}
        self.init_station_code()

    # 先抓取所有站点的代号并保存在.csv文件中
    def init_station_code(self):
        with open("station.csv", 'r', encoding='GBK') as fp:
            reader = csv.DictReader(fp)
            for line in reader:
                name = line['name']
                code = line['code']
                # 获取站点的代号
                self.station_codes[name] = code

2.4、你的登录信息

这步输入你的账号跟密码进行登录操作。

 class YourLoginClass:
        def __init__(self, login_url, personal_url, username, password):
            self.login_url = login_url
            self.personal_url = personal_url
            self.username = username
            self.password = password

            def login(self):
                driver.get(self.login_url)

                # 输入用户名和密码
                username_input = WebDriverWait(driver, 10).until(
                    EC.presence_of_element_located((By.NAME, '你的账号'))  # 替换 '' 为你网站上实际的用户名输入框的name属性值
                )
                password_input = WebDriverWait(driver, 10).until(
                    EC.presence_of_element_located((By.NAME, '你的密码'))  # 替换 '' 为你网站上实际的密码输入框的name属性值
                )

                username_input.send_keys(self.username)
                password_input.send_keys(self.password)

                # 提交表单
                password_input.submit()

                # 等待进入个人中心
                WebDriverWait(driver, 10).until(
                    EC.url_to_be(self.personal_url)
                )

2.5、你的站点信息

 class YourSearchClass:
        def __init__(self, left_tickets_url, station_codes, from_station, to_station, time_data, train_number):
            self.left_tickets = left_tickets_url
            self.station_codes = station_codes
            self.from_station = from_station
            self.to_station = to_station
            self.time_data = time_data
            self.train_number = train_number

        def search_ticket(self):
            driver.get(self.left_tickets)

            # 起始站的代号设置
            from_station_input = driver.find_element(by=By.ID, value="fromStation")
            from_station_code = self.station_codes.get(self.from_station, "")
            driver.execute_script("arguments[0].value='%s'" % from_station_code, from_station_input)

            # 终点站的代号设置
            to_station_input = driver.find_element(by=By.ID, value="toStation")
            to_station_code = self.station_codes.get(self.to_station, "")
            driver.execute_script("arguments[0].value='%s'" % to_station_code, to_station_input)

            # 设置时间
            train_date_input = driver.find_element(by=By.ID, value="train_date")
            driver.execute_script("arguments[0].value='%s'" % self.time_data, train_date_input)

            # 执行查询操作
            search_btn = driver.find_element(by=By.ID, value="query_ticket")
            search_btn.click()

            # 解析车次信息
            WebDriverWait(driver, 10).until(
                EC.presence_of_element_located((By.XPATH, "//tbody[@id='queryLeftTable']/tr"))
            )
            train_trs = driver.find_elements(by=By.XPATH, value="//tbody[@id='queryLeftTable']/tr[not(@datatran)]")

            # 定义一个变量,当选取到所需的座位时使变量变成True
            searched = False

            # 获得所有车票的信息
            for train_tr in train_trs:
                infos = train_tr.text.replace("\n", " ").split(" ")
                number = infos[0]

                # 从所有车票信息中选取自己所要的车票
                if number in self.train_number:
                    seat_types = self.train_number[number]
                    for seat_type in seat_types:
                        # 选取座位
                        if seat_type == "O":
                            count = infos[9]
                            if count.isdigit() or count == "有":
                                searched = True
                                break
                        elif seat_type == "D":
                            print("抢到D")
                        elif seat_type == "F":
                            print("抢到F")

            if searched:
                # 执行预定操作,例如点击预定按钮
                reserve_button = driver.find_element(by=By.XPATH, value="//button[@id='reserveButton']")
                reserve_button.click()

    class YourClass:
        def confirm_passengers(self):
            # 显式等待进入提交订单的url及乘客标签显示
            WebDriverWait(driver, 10).until(
                EC.url_contains(self.confirm_url)
            )
            WebDriverWait(driver, 10).until(
                EC.presence_of_element_located(
                    (By.XPATH, "//ul[@id='normal_passenger_id']/li/label/input[@type='checkbox']"))
            )

            # 确认需要购票的乘客
            passenger_checkboxes = driver.find_elements(By.XPATH,
                                                        "//ul[@id='normal_passenger_id']/li/label/input[@type='checkbox']")
            for checkbox in passenger_checkboxes:
                name = checkbox.get_attribute("innerText")
                if name == self.name:
                    checkbox.click()

            # 确认需要购买的席位信息
            seat_select = Select(driver.find_element(By.ID, "seatType_1"))
            seat_types = self.train_number[self.select_number]
            for seat_type in seat_types:
                try:
                    seat_select.select_by_value(seat_type)
                except NoSuchElementException:
                    continue
                else:
                    break

            # 等待提交按钮可以点击
            WebDriverWait(driver, 10).until(
                EC.element_to_be_clickable((By.ID, "submitOrder_id"))
            )
            # 点击提交订单
            submit_btn = driver.find_element(By.ID, "submitOrder_id")
            submit_btn.click()

2.6、判断是否成功

WebDriverWait(driver, 10).until(
                EC.presence_of_element_located((By.CLASS_NAME, "dhtmlx_window_active"))
            )
            WebDriverWait(driver, 10).until(
                EC.element_to_be_clickable((By.ID, "qr_submit_id"))
            )
            
            submit_btn = driver.find_element(By.ID, "qr_submit_id")

            # 可能需要连续点击
            while submit_btn.is_displayed():
                try:
                    submit_btn.click()
                except ElementNotVisibleException:
                    break

    def main():
        from_station = input("请输入起始站:")
        tostation = input("请输入终点站:")
        time_train = input("请输入订购车票时间(如2024-01-16):")
        person = input("请输入购票人姓名:")

    # 传参:起始站、终点站、时间、车次及所需座位(O为二等座、M为一等座)、购票人姓名
    # 在spider里面手动更改自己所需的车次及座位类别
        spider = train(from_station, tostation, time_train, {"D7137": ["O", "M"]}, person)
        spider.run()


if __name__ == '__main__':
    main()

三、项目总结

对于selenium是一个功能较为强大的一个自动化工具,可实现多种抢购活动。最后祝愿抢到了旅游的火车票的同学们,在抢票过程中如鱼得水。希望在成功抢到票后的旅行中体验不同的文化和风景。收获宝贵的经历和故事。希望大家期待着在旅途中收获美好的回忆,与喜欢的人一同分享快乐和欢笑,度过一个充实而难忘的假期!

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值