python爬虫(十七)12306案例

12306案例

学习目标

通过案例复习selenium的知识点,通过selenium抓取Ajax数据,使用Ajax技术,打开页面的时候不会完全显示内容,通过按钮操作后网页不会全部更新,实现部分界面的增量数据更新。只更新数据不刷新整个界面。

需求

人工操作12306的购票流程,让程序按照人操作的流程去模拟操作,这里登录界面需要扫码,先不处理验证框的问题。

步骤

第一步,登录;第二步,车次及余票的查询(点击查询按钮),进入购票界面;第三步,解析车次列表数据,人为的选择是通过肉眼判断的,要通过程序实现对车次列表的解析;第四步,确认乘客信息和席别;第五步,核对信息。

第一步登录

1.用类来实现12306的操作,用面向对象的方式搭建好整体的框架,通过实例化对象的方式把需要初始化的变量传递进去,实现部分函数的功能,登录成功之后,用显示等待去判断。
2.创建run函数用来调用使用的函数,先创建实现登录的函数,这里需要扫码进入(手动),之后判断登录成功后是否显示个人信息的界面,如果显示就是登录成功。

第二步车次以及余票的查询

​实现车次列表的查询
创建查票的函数,用驱动加载网站,用隐式等待暂停2秒,点击确定按钮,关闭弹窗。人为的操作是输入出发地、目的地和出发日,再点击查询,现在要浏览器模仿人的操作执行代码。在出发站输入框点右键,检查,光标定位到第二个input标签,但是在第一个input标签的value值中有出发地的代号,目的地同样存放的是城市的代号。我们选择出发地和目的地的时候需要把input里面的value值改成相应站台的代号。
在这里插入图片描述
需要把获得的代号文件导入进去,通过站台获得相应的代号。

得到站台相对应代号的字典
import csv
with open('stations.csv', 'r',encoding='utf-8') as f:
    read = csv.DictReader(f)  # 读出是两对值
    stations_dict = {}  # 组成一对字典
    for line in read:
        # print(line)
        name = line['name']
        code = line['code']
        stations_dict[name] = code
    print(stations_dict)

得到的字典在后续的函数中需要使用的,要把传入的站台转换为代号进行程序的执行,需要字典查询对应的代号。要在初始化的函数中定义字典,运行获得站台字典的函数,需要提前定义字典的变量,self.stations_dict = {},这样的话就可以在任何函数中都能使用,跨函数进行调用数据。
通过站台得到代号之后,要传入到value中。在查票函数中进行操作,先定位input标签,把输入的站台转换为代号,在12306程序内部只接收代号。这时运行会发现出发地和目的地输入框里没有内容,但是在网页空白处点右键,用元素选择器查看,每个框里是有相应的代码的。但是用右键进行检查发现代码中的value值又没了,那是因为右键进行检查的时候,对数据进行了刷新,数据又消失了,这是中途做的测试,不影响。
在这里插入图片描述
日期的value默认值永远都是那一天,不用管。把传入的日期放入value中。
在这里插入图片描述
出发地、目的地、日期输入完成之后,点击查询,进行车次的检索。
总结:
1 进入了查票的网页,需要等待页面加载几秒,然后处理弹窗
2 填入出发地、目的地和日期三个数据
- 定位到输入框
- 拿到站台的代号(日期是没有的 但是日期需要注意格式)
- 把站台代号填入标签的value中
3 点击查询按钮
这个步骤通过代码完成了车次及余票的查询

第三步解析车次列表的数据
页面分析

用selenium爬取就不用到网页源码中查看了,直接右键检查就可以了。找到任意一个车次,点右键,检查,定位到<a标签,里面的文本是车次,依次往上折叠标签,会发现需要的数据在<tr标签内,一个tr包含了一趟车次的所有数据,所有的tr都放到tbody标签里,每两个tr中都有一个无效的tr(光标放进去没有数据的指向)。
通过分析一个tr标签中存放了一趟车次的数据,所有的tr都存放于tbody标签中,其中夹杂了无效的tr标签,需要把无效的标签进行过滤。点击查询按钮会加载出来车次列表的数据,但是不知道是否完全加载出来。可以用显示等待,如果满足设定的条件,就说明车次列表数据是加载出来的。
在这里插入图片描述
无效的tr标签里有datatran属性,遍历取出的tr标签的时候可以根据这个属性过滤到无用的tr,对得到的tr进行遍历取值的时候,会发现车票数据里有的车次里多了“复”字,我们可以看到车次的信息是用"\n"进行分割,而有无票的数据是用空格分割的,我们可以先把"\n"换成空格,再用split(""),用空格进行切割,最后判断如果第二个字符为复,删掉"复"字。
在这里插入图片描述
车次是在分割后列表的第一个元素,用索引0取出,然后判断遍历取出的车次是否在传入的车次中,如果在的,就用字典把车次对应的坐席类型取出。先判断二等座,二等座在分割后列表的第十个,索引为9。如果取出的坐席是二等座,代码为O,就要判断车次和二等座交叉的位置是“有”或者数字就代表有票,否则是无票,如果有票的话进行点击操作;否则去判断一等座的情况。
在这里插入图片描述
如果一等座,二等座都有票的情况下,会出现先去选中二等座,点击预定按钮;之后再判断一等座的情况,再去点击预定。此时二等座点击完后页面会跳转,一等座再去点击预定的时候会找不到按钮,此时会报错。这时可以在解析完座位后用try语句。

代码实现
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import csv
"""用面向对象的方式搭建好整体的框架,通过实例化对象的方式把需要初始化的变量传递进去,实现部分函数的功能
登录成功之后,用显示等待去判断"""
class TrainSpider():
    """定义初始化方法 用类初始化对象,在实例化对象的时候把三个参数传进去,否则创建不成功"""
    def __init__(self, from_station, to_station, train_date, ticket_info):
        """

        :param from_station: 出发地
        :param to_station: 目的地
        :param train_date: 出发日期
        :param ticket_info: 车次以及坐席,9是特等坐,O是二等座,M是一等座
               {"G534":['O','M']},需要传到main里的参数里
        """
        self.from_station = from_station
        self.to_station = to_station
        self.train_date = train_date
        self.ticket_info = ticket_info
        self.driver = webdriver.Edge()
        # 登录的url
        self.logic_url = 'https://kyfw.12306.cn/otn/resources/login.html'
        # 个人界面的url
        self.person_url = 'https://kyfw.12306.cn/otn/view/index.html'
        # 查票的url
        self.query_url = 'https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc'
        # 存放字典和代号,可以跨函数调用,相当于全局,有站台名称可以随时调用
        self.stations_dict = {}
        # 初始化stations_dict,调用stations_code函数
        self.stations_code()

    # 得到站台以及对应代号的字典
    def stations_code(self):
        with open('stations.csv', 'r', encoding='utf-8') as f:
            read = csv.DictReader(f)  # 读出是两对值
            # stations_dict = {}  # 组成一对字典
            for line in read:
                # print(line)
                name = line['name']
                code = line['code']
                self.stations_dict[name] = code
                # self.stations_dict[line['name']] = line['code']
            # print(self.stations_dict)

    # 实现登录
    def logic(self):
        self.driver.get(self.logic_url)
        """用显示等待判断是否登录成功,传入驱动和最大等待时间,
        until()里设置等待的条件,跳转的界面里是否包含self.person_url里的地址 """
        WebDriverWait(self.driver, 1000).until(
            EC.url_contains(self.person_url)
        )  # 如果包含就显示登录成功。
        print("登录成功")
    # 查票
    def query_ticket(self):
        self.driver.get(self.query_url)
        # 用隐式等待2秒
        self.driver.implicitly_wait(2)
        # 关闭弹窗,点击弹窗的确定
        self.driver.find_element_by_id('qd_closeDefaultWarningWindowDialog_id').click()
        # 定位出发地输入框,要对value值进行改变,定位到有value值的input标签
        from_station_input = self.driver.find_element_by_id('fromStation')
        # 把输入的站台名转换成代号
        from_station_code = self.stations_dict[self.from_station]
        # 用js把代号传入value中,定位到input标签,然后往里输入转换后的代码值
        # self.driver.execute_script('arguments[0].value="%s"' % from_station_code, from_station_input)
        # 输入目的地,定位到目的地的输入框
        to_station_input = self.driver.find_element_by_id('toStation')
        # 输入的目的地的站台名转换为代号
        to_station_code = self.stations_dict[self.to_station]
        # 用js代码传入目的地的代号
        # self.driver.execute_script('arguments[0].value="%s"' % to_station_code, to_station_input)
    # 这时运行代码,出发地和目的地输入框里没有内容,但是在网页空白处点右键,用元素选择器查看,每个框里是有相应的代码的
        # 用id定位日期的输入标签,
        date_input = self.driver.find_element_by_id('train_date')
        # 用js代码传入日期
        # self.driver.execute_script('arguments[0].value="%s"' % self.train_date, date_input)

    # 以上三个框的输入也可以用一行代码实现,把每一个js传入的代码都注释掉,
        self.driver.execute_script('arguments[0].value="{}"; arguments[1].value="{}"; arguments[2].value="{}"'.format(from_station_code, to_station_code, self.train_date),from_station_input, to_station_input, date_input)
        # 定位到查询按钮,并进行点击
        self.driver.find_element_by_id('query_ticket').click()
        # 第三步 解析车次列表数据
        # 显示等待,等待车次列表数据加载完成
        WebDriverWait(self.driver, 1000).until(
            EC.presence_of_element_located((By.XPATH, './/tbody[@id="queryLeftTable"]/tr'))
        )
        # 获取车次列表
        # 过滤掉无效的tr标签
        train_trs = self.driver.find_elements_by_xpath('.//tbody[@id="queryLeftTable"]/tr[not(@datatran)]')
        try:
            for train_tr in train_trs:
                # print(train_tr.text)
                # print('*'*50)
                train_infos = train_tr.text.replace('\n', " ").split(" ")
                # 把“复”字从列表中删除
                if train_infos[1] == "复":
                    # remove把指定元素从列表中删除
                    train_infos.remove("复")
                train = train_infos[0]  # 从网页中爬取下来的车次,在init中实例化车次
                # 判断一下爬取下来的车次是否在传入的初始化车次中
                # train 是取到的车次,判断一下取到的一个个车次是否在传入的车次中
                if train in self.ticket_info:
                    # 如果在,就用传入字典格式的车次,去取后面的坐席
                    # 传入的{"G345": ['O', 'M']},先取O,再取M。
                    seat_types = self.ticket_info[train]
                    # 从seat_types里遍历出列出的车票类型,O,M
                    for seat_type in seat_types:
                        # 如果seat_type等于O,判断二等座是否有票
                        # 检查二等座对应的位置是否有余票
                        if seat_type == 'O':
                            # 在相应车次,二等奖交叉点处点右键,发现有票的话是“有”或者数字
                            # 从train_infos 的列表中可以看到,需要的信息在列表中第10个,索引是9
                            o_count = train_infos[9]
                            # 判断二等票的位置的内容是 “有”或者是数字
                            if o_count == "有" or o_count.isdigit():
                                # 如果满足,就点击预定按钮
                                # 光标在预定处点击右键,发现定位到tr标签下的a标签
                                train_tr.find_element_by_xpath('.//a[@class="btn72"]').click()
                                # 点击完预定后要退出,否则程序还会对一等座进行判断,如果一等座也有,会再次进行点击操作
                                # 二等座已经点击了,一等座在点击的时候页面已经跳转就找不到点击按钮,就会报错
                            break
                        elif seat_type == 'M':
                            # 如果要买一等座,就查看一等座的情况
                            # 找到下标索引为8的,为一等座
                            m_count = train_infos[8]
                            # 判断一等票的位置的内容是 “有”或者是数字
                            if m_count == "有" or m_count.isdigit():
                                # 如果满足,就点击预定按钮
                                # 光标在预定处点击右键,发现定位到tr标签下的a标签
                                train_tr.find_element_by_xpath('.//a[@class="btn72"]').click()
        except:
            pass

    # 实现函数的调用
    def run(self):
        # 第一步 登录
        self.logic()   # 调用函数
        # 第二步 车次及余票的查询
        self.query_ticket()
if __name__ == '__main__':
    # 通过创建的类去实例化对象,需要传递三个参数到init里
    # 注意日期的格式 yyyy-xx-xx
    spider = TrainSpider('长沙', '北京', '2021-09-15', {"G534": ['O', 'M']})
    spider.run()

有时会出现程序运行完成之后,网页自动关闭的情况。这涉及到垃圾回收机制,是因为用驱动打开浏览器是在类里面进行的操作,类运行结束后,相应的驱动也会结束,驱动随着类的消亡也消亡,这时候可以把驱动放到外面就可以了。

第四步确认乘客信息和席别

程序跳转到确认乘客信息和席别的url:https://kyfw.12306.cn/otn/confirmPassenger/initDc
这时我们是在同一个窗口进行的操作,会覆盖之前的浏览器地址。
这时的列车信息就不需要我们去操作了,是按照之前选择的内容进行选择的,乘客信息里面的内容需要进行点击操作,在这里点击姓名或者姓名前面的小框都可以选中乘客。需要进行的操作为:
1,确认乘客信息。可能会有多个人,以列表的形式在实例化对象的时候传进去。
用显示等待,看是否出现确认信息的网页,如果出现就等待成功。光标在乘客姓名处点右键,发现乘客信息是在li标签下的label里,如果有多个乘客会分别出现在多个li标签里面。li标签都在ul标签内,我们要先定位到ul标签,然后在里面找到li标签的文本值。这里找到的乘车人有多个,所以要在element后加个s,返回的是所有乘车人的列表。遍历取出每一个乘车人,看是否在实例化对象时候传入的乘车人姓名列表中,如果在,就点击乘车人的标签进行选中。
2,确认坐席。需要用selenium操作下拉菜单。在席别下拉框中点击,进行选中操作,点右键检查,定位到select标签,操作之前需要导入select类。
在这里插入图片描述

利用id定位到席别选择框,导入select类,把定位到的选择框传入select类中进行操作,这里可以看到O代表二等座,M代表一等座,9代表商务座,这时只需要把每个座位的value值传入到select中进行选择即可。
3,点击提交订单按钮。

第五步 核对信息

用显示等待进行判断,如果出现核对信息框,就进行点击。
完整的代码实现如下:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select  # 第四步确认坐席时使用
import time
import csv
"""用面向对象的方式搭建好整体的框架,通过实例化对象的方式把需要初始化的变量传递进去,实现部分函数的功能
登录成功之后,用显示等待去判断"""
class TrainSpider():
    """定义初始化方法 用类初始化对象,在实例化对象的时候把三个参数传进去,否则创建不成功"""
    def __init__(self, from_station, to_station, train_date, ticket_info, passengers):
        """

        :param from_station: 出发地
        :param to_station: 目的地
        :param train_date: 出发日期
        :param ticket_info: 车次以及坐席,9是特等坐,O是二等座,M是一等座
               {"G534":['O','M']},需要传到main里的参数里
        :param passengers: 第四步添加的,需要乘车的人
        """
        self.from_station = from_station
        self.to_station = to_station
        self.train_date = train_date
        self.ticket_info = ticket_info
        self.passengers = passengers
        self.driver = webdriver.Edge()
        # 第一步登录的url
        self.logic_url = 'https://kyfw.12306.cn/otn/resources/login.html'
        # 第一步个人界面的url
        self.person_url = 'https://kyfw.12306.cn/otn/view/index.html'
        # 第二步查票的url
        self.query_url = 'https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc'
        # 第四步确认信息的url
        self.confirm_url = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
        # 存放字典和代号,可以跨函数调用,相当于全局,有站台名称可以随时调用

        self.stations_dict = {}
        # 初始化stations_dict,调用stations_code函数
        self.stations_code()
        # 定义选择信息为空,在第四步席别选择框中使用,先定义为空值,把第三步得到的seat_type赋值给它
        self.select_info = None

    # 得到站台以及对应代号的字典
    def stations_code(self):
        with open('stations.csv', 'r', encoding='utf-8') as f:
            read = csv.DictReader(f)  # 读出是两对值
            # stations_dict = {}  # 组成一对字典
            for line in read:
                # print(line)
                name = line['name']
                code = line['code']
                self.stations_dict[name] = code
                # self.stations_dict[line['name']] = line['code']
            # print(self.stations_dict)

    # 实现登录
    def logic(self):
        self.driver.get(self.logic_url)
        """用显示等待判断是否登录成功,传入驱动和最大等待时间,
        until()里设置等待的条件,跳转的界面里是否包含self.person_url里的地址 """
        WebDriverWait(self.driver, 1000).until(
            EC.url_contains(self.person_url)
        )  # 如果包含就显示登录成功。
        print("登录成功")
    # 查票
    def query_ticket(self):
        self.driver.get(self.query_url)
        # 用隐式等待2秒
        self.driver.implicitly_wait(2)
        # 关闭弹窗,点击弹窗的确定
        self.driver.find_element_by_id('qd_closeDefaultWarningWindowDialog_id').click()
        # 定位出发地输入框,要对value值进行改变,定位到有value值的input标签
        from_station_input = self.driver.find_element_by_id('fromStation')
        # 把输入的站台名转换成代号
        from_station_code = self.stations_dict[self.from_station]
        # 用js把代号传入value中,定位到input标签,然后往里输入转换后的代码值
        # self.driver.execute_script('arguments[0].value="%s"' % from_station_code, from_station_input)
        # 输入目的地,定位到目的地的输入框
        to_station_input = self.driver.find_element_by_id('toStation')
        # 输入的目的地的站台名转换为代号
        to_station_code = self.stations_dict[self.to_station]
        # 用js代码传入目的地的代号
        # self.driver.execute_script('arguments[0].value="%s"' % to_station_code, to_station_input)
    # 这时运行代码,出发地和目的地输入框里没有内容,但是在网页空白处点右键,用元素选择器查看,每个框里是有相应的代码的
        # 用id定位日期的输入标签,
        date_input = self.driver.find_element_by_id('train_date')
        # 用js代码传入日期
        # self.driver.execute_script('arguments[0].value="%s"' % self.train_date, date_input)

    # 以上三个框的输入也可以用一行代码实现,把每一个js传入的代码都注释掉,
        self.driver.execute_script('arguments[0].value="{}"; arguments[1].value="{}"; arguments[2].value="{}"'.format(from_station_code, to_station_code, self.train_date),from_station_input, to_station_input, date_input)
        # 定位到查询按钮,并进行点击
        self.driver.find_element_by_id('query_ticket').click()
        # 第三步 解析车次列表数据
        # 显示等待,等待车次列表数据加载完成
        WebDriverWait(self.driver, 1000).until(
            EC.presence_of_element_located((By.XPATH, './/tbody[@id="queryLeftTable"]/tr'))
        )
        # 获取车次列表
        # 过滤掉无效的tr标签
        train_trs = self.driver.find_elements_by_xpath('.//tbody[@id="queryLeftTable"]/tr[not(@datatran)]')
        # 定义标志位,用来判断是否找到用户需要购买的车次和坐席,如果找到就改为True
        # False的默认值为0
        flag = False
        for train_tr in train_trs:
            # print(train_tr.text)
            # print('*'*50)
            train_infos = train_tr.text.replace('\n', " ").split(" ")
            # 把“复”字从列表中删除
            if train_infos[1] == "复":
                # remove把指定元素从列表中删除
                train_infos.remove("复")
            train = train_infos[0]  # 从网页中爬取下来的车次,在init中实例化车次
            # 判断一下爬取下来的车次是否在传入的初始化车次中
            # train 是取到的车次,判断一下取到的一个个车次是否在传入的车次中
            if train in self.ticket_info:
                # 如果在,就用传入字典格式的车次,去取后面的坐席
                # 传入的{"G345": ['O', 'M']},先取O,再取M。
                seat_types = self.ticket_info[train]
                # 从seat_types里遍历出列出的车票类型,O,M
                for seat_type in seat_types:
                    # 如果seat_type等于O,判断二等座是否有票
                    # 检查二等座对应的位置是否有余票
                    if seat_type == 'O':
                        # 在相应车次,二等奖交叉点处点右键,发现有票的话是“有”或者数字
                        # 从train_infos 的列表中可以看到,需要的信息在列表中第10个,索引是9
                        o_count = train_infos[9]
                        # 判断二等票的位置的内容是 “有”或者是数字
                        if o_count == "有" or o_count.isdigit():
                            # 如果满足,就点击预定按钮
                            # 光标在预定处点击右键,发现定位到tr标签下的a标签
                            # train_tr.find_element_by_xpath('.//a[@class="btn72"]').click()
                            # # 点击完预定后要退出,否则程序还会对一等座进行判断,如果一等座也有,会再次进行点击操作
                            # # 二等座已经点击了,一等座在点击的时候页面已经跳转就找不到点击按钮,就会报错
                            self.select_info = seat_type
                            flag = True  # 如果找到了,就把标志位改为True
                            break  # 退出判断坐席有无的操作
                    elif seat_type == 'M':
                        # 如果要买一等座,就查看一等座的情况
                        # 找到下标索引为8的,为一等座
                        m_count = train_infos[8]
                        # 判断一等票的位置的内容是 “有”或者是数字
                        if m_count == "有" or m_count.isdigit():
                            # 如果满足,就点击预定按钮
                            # 光标在预定处点击右键,发现定位到tr标签下的a标签
                            # train_tr.find_element_by_xpath('.//a[@class="btn72"]').click()
                            self.select_info = seat_type
                            flag = True  # 如果找到了,就把标志位改为True
                            break
                if flag:  # 如果找到了就进行点击
                    train_tr.find_element_by_xpath('.//a[@class="btn72"]').click()
                    break  # 退出选坐席的操作

    # 确认乘客信息
    def confirm_passengers(self):
        # 显示等待,判断是否成功跳转到确认乘客信息界面
        # 如果跳转到confirm_url,则说明页面跳转成功。
        WebDriverWait(self.driver, 1000).until(
            EC.url_contains(self.confirm_url)
        )
        # 确认乘客信息,乘客信息是在li标签下的label里,所有的li都在ul标签里
        # 返回多个内容,改为elements,返回的是个列表
        passenger_labels = self.driver.find_elements_by_xpath('.//ul[@id="normal_passenger_id"]/li/label')
        # 这里的乘车人要跟传进来的乘车人进行对比,需要在实例化对象的时候传入乘车人,在初始化的时候接收参数
        for passenger in passenger_labels:
            name = passenger.text  # 定位到乘车人标签之后,遍历取出乘车人的文本
            if name in self.passengers:
                passenger.click()  # 如果找到的乘车人在传入的参数中,进行点击

        # 确认坐席
        # 定位到席别选项框
        seat_tag = self.driver.find_element_by_id('seatType_1')
        # 把定位到的选择框座位参数传入到Select类里才能进行操作
        seat_select = Select(seat_tag)
        # 可以利用上个函数里 选中二等座或者一等座的结果放到select里传参进行选择
        # 这时就需要定义个全局的变量select_info,把找到的seat_type赋值给select_info
        seat_select.select_by_value(self.select_info)
        # 第一种方法
        # 点击提交订单按钮,通过id定位
        self.driver.find_element_by_id('submitOrder_id').click()

        # 第二种方法:
        # 在119和121行的seat_types,改为self.select_info,135和147行注释掉
        # 下面的语句中,比如找到了二等座
        # for seat in self.select_info:  # 遍历出列表中的坐席
        #     try:
        #         seat_select.select_by_value(seat)  # 对每一个坐席进行选择
        #         # 如果没问题就进行选择,如果找不到就继续遍历下一个坐席
        #     except:
        #         continue
        #     else:
        #         break
        #     # 如果没问题就执行try和else里的语句,如果找的二等座有异常,就去寻找一等座,找到合适的坐席就退出
        #     # 相当于又去寻找了一次实例化传入列表的坐席

        # 第五步 核对信息
        # 用显示等待 判断核对信息框是否出现,传入核对框的ID。
        WebDriverWait(self.driver, 1000).until(
            EC.presence_of_element_located((By.ID, 'content_checkticketinfo_id'))
        )
        # 如果消息框出现,点击确认按钮
        # time.sleep(2)
        self.driver.find_element_by_id('qr_submit_id').click()

    """功能模块的使用,封装基本的功能,如果把登录,查询,确认的内容都写在一个函数里,
    就会特别臃肿,可以封装不同的函数实现不同的功能,在一个函数中进行调用"""
    # 实现函数的调用
    def run(self):
        # 第一步 登录
        self.logic()   # 调用函数
        # 第二步 车次及余票的查询,第三步 车票数据解析
        self.query_ticket()
        # 第四步 确认乘客信息和席别
        self.confirm_passengers()

if __name__ == '__main__':
    # 通过创建的类去实例化对象,需要传递三个参数到init里
    # 注意日期的格式 yyyy-xx-xx
    spider = TrainSpider('长沙', '北京', '2021-09-15', {"G534": ['O', 'M']}, ['乘客姓名1', '乘客姓名2'])
    spider.run()
  • 3
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值