selenium实现12306购票

selenium实现12306购票
	第一个问题我们这个案例的初衷是干什么?
	第二个问题是这个案例和专业打保票的差别
	第三个问题 登录是可以提前登录的。 但是登录又是必须的

第一步 登录
	面向对象来完成知识点复习
	浏览器的闪退问题 如何产生的 如何解决的
	显示等待
第二步 车次以及余票查询
	由个人详情界面跳转到车次界面
	先要获取所有的站点以及对应的编号-->把数据存到字典当中key name value code
	输入出发地 输入目的地 输入出发日期
		1.定位input标签
		2.获取编号
		3.driver.excute_script()方法来设置隐藏标签 code设置到value里面
		4.定位查询按钮 点击查询 出现车次列表
第三步 解析车次列表
	**显示等待**车次列表(条件 是这些 tr 标签加载完成)
	车次列表的分析 tbody标签下面的 tr 标签 过滤没有车次信息的 tr 标签
     driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr[not(@datatran)]')
	替换拼接的方式把车次信息的数据放到一个列表里面
	init方法里面初始化了一个用户的车次 先获得了这个车次 做了一个判断 判断这个数据在我们的初始化信息里面
	然后进行 我们想要买的车次的数据解析
第四步 确认乘客信息
	显示等待 判断是否是确认乘客信息页面
	显示等待是否乘客标签加载出来了 
	init方法里面 初始化了乘客信息[xxx, xxx]
	确定席位select标签  Select类下标value	
	二等座如果没有了 NoSuchElementException  try except 点击提交按钮
	  	最终的确认信息
	  	等待这个确认菜单加载出来
	  	定位确定按钮 提交订单 就会在12306后台生成一个订单
	  	有可能会点击不到这个确定按钮 可以定义一个循环来不断点击 直到它抛出异常 就证明我们点击					到了 订单就提交成功了
	

12306.py

# @ Time : 2021/3/5 12:28
# @ Author : Ellen

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.ui import Select
import csv
from selenium.common.exceptions import NoSuchElementException, ElementNotVisibleException

driver = webdriver.Chrome() # 驱动放在全局变量当中 放在类中随着类的销亡驱动也会被销毁 页面会出现闪退情况

class TrainSpider():
    # url放在类对象中 也不要放在__init__ 或者方法里面 放进去就是实例化属性了
    login_url = 'https://kyfw.12306.cn/otn/resources/login.html'  # 登录的url
    personal_url = 'https://kyfw.12306.cn/otn/view/index.html'  # 个人信息的url
    left_ticket_url = 'https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc'  # 车次的url
    confirm_passengers_url = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc' # 确认乘客信息的url


    def __init__(self, from_station, to_station, train_date, trains, passengers):
        '''
        :param from_station: 出发地
        :param to_station: 目的地
        :param train_date: 出发日期
        :param trains: 想要购买的车次及席位{'k21':['O', 'M']}
        :param passengers: 想要买票乘客的姓名 [xxx,xxx...]
        '''
        self.from_station = from_station
        self.to_station = to_station
        self.trains = trains
        self.train_date = train_date
        self.passengers = passengers
        self.selected_number = None

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

    def init_station_code(self):
        with open('stations.csv', 'r', encoding='utf-8') as f:
            reader = csv.DictReader(f)
            for i in reader:
                name = i['name']
                code = i['code']
                self.station_codes[name] = code

    def login(self):
        driver.get(self.login_url)
        # 显示等待
        WebDriverWait(driver, 1000).until(
            EC.url_contains(self.personal_url)
        )
        print('登录成功')

    def search_left_Ticket(self):
        driver.get(self.left_ticket_url)
        # 要输入出发地  出发日期
        from_station_input = driver.find_element_by_id('fromStation')
        from_station_code = self.station_codes[self.from_station]
        # arguments[0]对应的是第一个参数 type = 'hidden'
        driver.execute_script('arguments[0].value="%s"' % from_station_code, from_station_input)
        # 目的地
        to_station_input = driver.find_element_by_id('toStation')
        to_station_code = self.station_codes[self.to_station]
        driver.execute_script('arguments[0].value="%s"' % to_station_code, to_station_input)
        # 出发日期
        train_date_input = driver.find_element_by_id('train_date')
        # train_date_input.send_keys(self.train_date)  虽然不是type = 'hidden'隐藏标签 用常send_keys 无法把日期添加进去 还是用的execute_script()方法
        driver.execute_script('arguments[0].value="%s"' % self.train_date, train_date_input)

        # 定位查询按键并且点击查询
        search_btn = driver.find_element_by_id('query_ticket')
        search_btn.click()

        # 解析车次信息
        WebDriverWait(driver, 1000).until(
            EC.presence_of_element_located((By.XPATH, '//tbody[@id="queryLeftTable"]/tr'))
        )
        # 定位车次信息的tr标签 并且过滤掉没有数据的tr标签
        train_trs = driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr[not(@datatran)]')
        is_searched = False
        for train_tr in train_trs:
            # print(train_tr.text)
            # 替换并分割数据-->车次列表 replace('\n', ' ') ->换行替换空格 split(' ')->分割空格
            infos = train_tr.text.replace('\n', ' ').split(' ')
            number = infos[0]
            if number in self.trains:
                seat_types = self.trains[number]
                for seat_type in seat_types:
                    if seat_type == 'O':
                        # O找的是二等座
                        count = infos[9]
                        if count.isdigit() or count == '有':
                            is_searched = True
                            break
                    elif seat_type == 'M':
                        # M找的是一等座
                        count = infos[8]
                        if count.isdigit() or count == '有':
                            is_searched = True
                            break
                if is_searched:
                    self.selected_number = number
                    order_tbn = train_tr.find_element_by_xpath('.//a[@class="btn72"]')
                    order_tbn.click()
                    break

    def confirm_passengers(self):
        WebDriverWait(driver, 1000).until(
            EC.url_contains(self.confirm_passengers_url)
        )
        # 等待乘客的标签信息 显示出来了 我们再定位点击事件
        WebDriverWait(driver, 1000).until(
            EC.presence_of_all_elements_located((By.XPATH, '//ul[@id="normal_passenger_id"]/li/label'))
        )
        passengers_labels = driver.find_elements_by_xpath('//ul[@id="normal_passenger_id"]/li/label')
        for passengers_label in passengers_labels:
            name = passengers_label.text
            if name in self.passengers:
                passengers_label.click()

            # 确认购买席位的信息
            seat_select = Select(driver.find_element_by_id('seatType_1'))
            seat_types = self.trains[self.selected_number]
            for seat_type in seat_types:
                try:
                    seat_select.select_by_value(seat_type)
                except NoSuchElementException:
                    continue
                else:
                    break
            submit_btn = driver.find_element_by_id('submitOrder_id')
            submit_btn.click()

            WebDriverWait(driver, 1000).until(
                EC.presence_of_all_elements_located((By.CLASS_NAME, 'dhtmlx_window_active'))
            )

            sub_btn = driver.find_element_by_id('qr_submit_id')
            while sub_btn:
                try:
                    sub_btn.click()
                    sub_btn = driver.find_element_by_id('qr_submit_id')
                except ElementNotVisibleException:
                    break


    def run(self):
        # 1 登录
        self.login()
        # 2 车次及余票查询
        self.search_left_Ticket()
        # 3 确认乘客和席位信息
        self.confirm_passengers()


def main():
    # 实例化对象
    spider = TrainSpider('北京', '长沙', '2021-03-09', {'G485': ['O', 'M']}, ['xxx'])
    spider.run()


if __name__ == '__main__':
    main()

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
【为什么学爬虫?】        1、爬虫入手容易,但是深入较难,如何写出高效率的爬虫,如何写出灵活性高可扩展的爬虫都是一项技术活。另外在爬虫过程中,经常容易遇到被反爬虫,比如字体反爬、IP识别、验证码等,如何层层攻克难点拿到想要的数据,这门课程,你都能学到!        2、如果是作为一个其他行业的开发者,比如app开发,web开发,学习爬虫能让你加强对技术的认知,能够开发出更加安全的软件和网站 【课程设计】 一个完整的爬虫程序,无论大小,总体来说可以分成三个步骤,分别是:网络请求:模拟浏览器的行为从网上抓取数据。数据解析:将请求下来的数据进行过滤,提取我们想要的数据。数据存储:将提取到的数据存储到硬盘或者内存中。比如用mysql数据库或者redis等。那么本课程也是按照这几个步骤循序渐进的进行讲解,带领学生完整的掌握每个步骤的技术。另外,因为爬虫的多样性,在爬取的过程中可能会发生被反爬、效率低下等。因此我们又增加了两个章节用来提高爬虫程序的灵活性,分别是:爬虫进阶:包括IP代理,多线程爬虫,图形验证码识别、JS加密解密、动态网页爬虫、字体反爬识别等。Scrapy和分布式爬虫:Scrapy框架、Scrapy-redis组件、分布式爬虫等。通过爬虫进阶的知识点我们能应付大量的反爬网站,而Scrapy框架作为一个专业的爬虫框架,使用他可以快速提高我们编写爬虫程序的效率和速度。另外如果一台机器不能满足你的需求,我们可以用分布式爬虫让多台机器帮助你快速爬取数据。 从基础爬虫到商业化应用爬虫,本套课程满足您的所有需求!【课程服务】 专属付费社群+定期答疑

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值