12306预售车票 时间是2019年的哈 (记笔记)

本文详细解析了一个Python自动化抢火车票的程序,包括利用Selenium库进行网页交互,从CSV文件获取车站代码,登录验证,车次余票查询,选择席位和乘客信息,以及异常处理。程序通过等待元素出现确保页面加载完成,提高了抢票效率。
摘要由CSDN通过智能技术生成

先说明一下哈,这个是从视频上面我搬运的哈,视频时间2019的,代码应该没用
我只是单纯的做笔记哈,写一哈自己的感受哈

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.select import Select
from selenium.common.exceptions import NoSuchElementException,ElementNotVisibleException  #这是导入一个异常哦
import csv


driver=webdriver.Chrome()     #将driver 设置为全局变量 是因为 如果放在里面 driver会随着 对象的销毁 而 被销毁

class TrainSpider(object):
    login_url='登陆界面url'       #定义在这里 可以随时  改变 url
    presonal_url='这里是登陆后跳转的url   来判断是否登陆成功'
    left_ticket_url='车次余票url'
    confirm_passengner_url='确认乘客页面的url'

    def __init__(self,from_station,to_station,train_date,trains,passengers):
        '''

        :param from_station: 起始站
        :param to_station: 目的站
        :param train_date: 出发目标
        :param trains: 需要购买车次    是一个字典 传入实例:{'G529':['M','O'],'G403':{'M','O'}}
        :param passengers: 乘客的姓名   是一个列表 传入实例: ['乘客名','乘客名','乘客名',]
        '''
        self.from_station=from_station
        self.to_station=to_station
        self.train_date=train_date
        self.trains=trains
        self.passengers=passengers       #将 传过来的 变量 保存在对象上
        self.selected_seat=None
        self.selected_number=None        #自己定义类中全局变量   定义了 车号 和 席位

        #self.driver=webdriver.Chrome()  放在里面可以方便 输出 有联想

        self.station_codes={}       #定义(在外面而非 函数里里面) 变量  因为  车票 查询 需要
        self.init_station_code()   #初始化站点所对应的代号     一开始自动运行函数


    def init_station_code(self):      #这个是得到站点的代号   为了输入车票的起始点
        with open('z stations.csv', 'r', encoding='utf-8') as fp:
            reader = csv.DictReader(fp)
            for line in reader:
                name = line['name']
                code = line['code']
                self.station_codes[name] = code

    def login(self):
        driver.get(self.login_url)
        #等待url 是否变为个人中心的url 来判断 是否登陆成功   (设置显示等待)
        WebDriverWait(driver,1000).until(
            #判断条件
            #EC.url_to_be(self.presonal_url)   变成这个url
            EC.url_contains(self.presonal_url)  #包含这个url
        )
        print('登陆成功!')

    def search_left_ticket(self):
        driver.get(self.left_ticket_url)
       #1.起始站代号设置
        from_station_input = driver.find_element_by_id("fromStation")
        from_station_code=self.station_codes[self.from_station]
        '''self.station_codes[name] = code      因为这个 所以可以 返回 地点 代号'''
        driver.execute_script(f"arguments[0].value='{from_station_code}'" , from_station_input)  #设置值到框框
        #这种josnscript 设置值   一切情况     都   适用
        '''因为type 是 hidden 被隐藏   所以需要采用josnscript代码来实现
        arguments  代表   你给函数   传的参数    是一个列表
        "arguments[0].value='%s'" % from_code 是 json代码
        from_station_input 传的参数   如果有其他的参数 都   放在 arguments中'''
        #2.终点站代号设置
        to_station_input = driver.find_element_by_id("toStation")
        to_station_code = self.station_codes[self.to_station]
        driver.execute_script(f"arguments[0].value='{to_station_code}'", to_station_input)
        #3.设置时间
        train_date_input = driver.find_element_by_id("train_date")
        driver.execute_script(f'arguments[0].value={self.train_date}',train_date_input)

        #4.执行查询操作
        search_btn=driver.find_element_by_id('query_ticket')
        search_btn.click()

        #5.解析车次信息
        WebDriverWait(driver,1000).until(
            EC.presence_of_element_located((By.XPATH,"//tbody[@id='queryLeftTable']/tr"))
        )
        train_trs=driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr[not(@datatran)]')
        #tr[not(@datatran)]  可以排除  含有 datatran 条件的 tr
        is_searched=False
        while True:             #这个 死循环  是为了多次查询  因为有些票时间没到 还在准备预售   之前不加这个 就只查询一次就没了
            for train_tr in train_trs:
                #print(train_tr.text)
                infos=train_tr.text.repalce('\n',' ').split(' ')
                #print(infos)
                number=infos[0]
                if number in self.trains:       #判断key(车号)是否在 字典  trains
                    seat_types=self.trains[number]    #如果有key(车号) 获得车号需要的 seat_types
                    for seat_type in seat_types:      #遍历这个车号的所有 信息
                        #是否有二等座
                        if seat_type == 'O':          #遍历是否有 座位为二等座的  就可以进行下面的判断二等座是否有
                            count=infos[9]
                            if count.isdigit() or count == '有':
                                is_searched=True
                                break

                        #是否有一等座
                        elif seat_type == 'M':
                            count=infos[8]
                            if count.isdigit() or count == '有':
                                is_searched=True
                                break

                if is_searched:
                    self.selected_number=number
                    order_btn = train_tr.find_element_by_xpath('.//a[@class="btn72"]')
                    order_btn.click()
                    return


    def confirm_passengers(self):
        #1.判断是否变为确认乘客的url页面  和 等待 确认购买乘客信息的出现
        WebDriverWait(driver,1000).until(
            EC.url_contains(self.confirm_passengner_url)
        )
           #先等待乘客标签显示出来
        WebDriverWait(driver,1000).until(
            EC.presence_of_element_located((By.XPATH,'//ul[@id="normal_passenger_id"]/li/label'))
        )
        #2.确认需要购买车票的乘客
        passenger_labels=driver.find_elements_by_xpath('//ul[@id="normal_passenger_id"]/li/label')
        for passenger_label in passenger_labels:
            name=passenger_label.text
            if name in self.passengers:
                passenger_label.click()
        #3.确认需要购买的席位信息
        seat_select=Select(driver.find_element_by_id('seatType_1'))
        seat_types=self.trains[self.selected_number]     #是一个列表
        '''self.trains[self.selected_number]   因为传过来的trains 是一个字典 所以可以通过key索引'''
        for seat_type in seat_types:
            try:
                self.selected_seat =seat_type
                seat_select.select_by_value(seat_type)
            except NoSuchElementException:        #捕捉异常
                continue                          #continue 就是 下次循环下一个座次
            else:
                break                             #如果第一次就找到啦 就退出循环
        #等待 提交订单按钮可以被点击
        WebDriverWait(driver,1000).until(
            EC.element_to_be_clickable((By.ID,'submintOrder_id'))
        )

        submit_btn=driver.find_element_by_id('submintOrder_id')
        submit_btn.click()
        #等待 模拟对话框出现 和 确认按钮可以点击
        WebDriverWait(driver,1000).until(
            EC.presence_of_element_located((By.CLASS_NAME,'dhtmlx_window_active'))
        )
           #确认按钮可以点击
        WebDriverWait(driver,1000).until(
            EC.element_to_be_clickable((By.ID,"qr_submit_id"))
        )
        submit_btn=driver.find_element_by_id("qr_submit_id")
        #submit_btn.click()    #有可能 点击一次并不会出来 所以采用下面的   暴力循环点击
        while submit_btn:
            try:

                submit_btn.click()
                submit_btn = driver.find_element_by_id("qr_submit_id")
            except ElementNotVisibleException:
                # 会报这个错 ElementNotVisibleException 说明页面已经换了 即代表成功了 就可以退出循环
                break
        print(f"恭喜!成功抢{self.selected_number}次列车{self.selected_seat}席位,请在30分钟内完成付款!" )


    def run(self):                   # 一切相关的就放在这    相当于总控制者
      #1.登录 ()       定义一个 函数一个
        self.login()
      #2.车次余票查询
        self.search_left_ticket()
      #3.确认乘客和车次信息
        self.confirm_passengers()


def main():
    # 9:商务座,M:一等座,O:二等座,3:硬卧,4:软卧,1:硬座
    from_station=input('请输入出发地:')
    to_station=input('请输入目的地:')
    train_date=str(input('请输入出发时间(请按照如下格式输入时间: 2020-13-14):'))
    train_number=input('你准备乘坐的车号(车号实例:G520):')
    train_seat=input ("请输入座位级别(输入实例:m o):").split()
    train={train_number:train_seat}
    passenger_names=input ("输入名字(输入实例:小明 小红):").split()
    spider=TrainSpider(from_station,to_station,train_date,train,passenger_names)
    spider.run()


if __name__ == '__main__':
    main()
  1. 这里对 类中的 参数的传入和设置 有了新的 理解 之前没么怎么使用过类
    对参数的 传入 和 设置

传入 我自己的理解 就相当于 c语言中 对函数传值一样那种 只不过在类中使用 需要初始化(self.from_station=from_station我也不知道这个是不是叫初始化)

设置嘛 就是平时一样的 就使用的时候 加个self

   def __init__(self,from_station,to_station,train_date,trains,passengers):
        '''

        :param from_station: 起始站
        :param to_station: 目的站
        :param train_date: 出发目标
        :param trains: 需要购买车次    是一个字典 传入实例:{'G529':['M','O'],'G403':{'M','O'}}
        :param passengers: 乘客的姓名   是一个列表 传入实例: ['乘客名','乘客名','乘客名',]
        '''
        self.from_station=from_station
        self.to_station=to_station
        self.train_date=train_date
        self.trains=trains
        self.passengers=passengers       #将 传过来的 变量 保存在对象上
        self.selected_seat=None
        self.selected_number=None        #自己定义类中全局变量   定义了 车号 和 席位

        #self.driver=webdriver.Chrome()  放在里面可以方便 输出 有联想

        self.station_codes={}       #定义(在外面而非 函数里里面) 变量  因为  车票 查询 需要
        self.init_station_code()   #初始化站点所对应的代号     一开始自动运行函数

对于 driver.execute_script(f"arguments[0].value='{from_station_code}'" , from_station_input) 这个认识

driver.execute_script(f"arguments[0].value='{from_station_code}'" , from_station_input)  #设置值到框框
        #这种josnscript 设置值   一切情况     都   适用
        '''因为type 是 hidden 被隐藏   所以需要采用josnscript代码来实现
        arguments  代表   你给函数   传的参数    是一个列表
        "arguments[0].value='%s'" % from_code 是 json代码
        from_station_input 传的参数   如果有其他的参数 都   放在 arguments中'''

3.以及 处处都需要显示等待的条件 思维

 #1.判断是否变为确认乘客的url页面  和 等待 确认购买乘客信息的出现
        WebDriverWait(driver,1000).until(
            EC.url_contains(self.confirm_passengner_url)
        )
           #先等待乘客标签显示出来
        WebDriverWait(driver,1000).until(
            EC.presence_of_element_located((By.XPATH,'//ul[@id="normal_passenger_id"]/li/label'))
        )

4.以及输出列表的方式

passenger_names=input ("输入名字(输入实例:小明 小红):").split()
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值