爬虫案例:12306自动抢票,异常处理

异常处理

所有webdriver代码中发生的异常:

  • selenium.common.exceptions.WebDriverException :webdriver基本异常
  • selenium.common.exceptions.UnknownMethodException :请求的命名与URL匹配但该URL方法不匹配
  • selenium.common.exceptions.UnexpectedTagNameException :当支持类没有获得预期的Web元素时抛出
  • selenium.common.exceptions.UnexpectedAlertPresentException :出现意外警报时抛出,通常在预期模式阻止webdriver表单执行任何更多命令时引发
  • selenium.common.exceptions.UnableToSetCookieException :当驱动程序无法设置cookie时抛出
  • selenium.common.exceptions.TimeoutException :当命令没有在足够的时间内完成时抛出
  • selenium.common.exceptions.StaleElementReferenceException :当对元素的引用现在“陈旧”时抛出,陈旧意味着该元素不再出现在页面的DOM上
  • selenium.common.exceptions.SessionNotCreatedException :无法创建新会话
  • selenium.common.exceptions.ScreenshotException :屏幕截图错误异常
  • selenium.common.exceptions.NoSuchWindowException :当不存在要切换的窗口目标时抛出
  • selenium.common.exceptions.NoSuchElementException :无法找到元素时抛出
  • selenium.common.exceptions.NoSuchCookieException :在当前浏览上下文的活动文档的关联cookie中找不到与给定路径名匹配的cookie
  • selenium.common.exceptions.NoSuchAttributeException :无法找到元素的属性时抛出
  • selenium.common.exceptions.JavascriptException :执行用户提供的JavaScript时发生错误

自动抢票

第一次写这么长的,,,感觉发际线高了几分

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
from selenium.common.exceptions import NoSuchElementException  # 表单元素如果不存在就抛出这个异常
import csv
import time

driver = webdriver.Chrome()  # 不能放到类里面哦,在网页打开后,main 函数执行完毕,就会自动删除保存的变量,包括driver,所以网页就会自动关闭


# 9:商务座,M:一等座,O:二等座,3:硬卧,4:软卧,1:硬座  12306有专门对应的代号
class TrainSpider:
    def __init__(self, fstation, tstation, date, trains, passengers):
        # 在pycham中,三对双引号可以自动给你注释
        """
        :param fstation: 出发地
        :param tstation: 目的地
        :param date: 出发日期
        :param trains: 需要购买的车次,与可以接受的席别,需要一个字典{“K884”:[“M”,"O"]}
        :param passengers:乘客的姓名需要一个列表
        """
        self.fstation = fstation
        self.tstation = tstation
        self.trains = trains
        self.date = date
        self.passengers = passengers
        self.station_codes = {}  # 站点代码
        self.select_number = None  # 我们选择的车次
        self.station_code()   # 调用函数

    def station_code(self):  # 获得地区代码,12306的站点使用的是代号,这里我把代号保存在了stations。csv这个文件里
        with open('stations.csv', encoding='utf-8') as f:
            reader = csv.DictReader(f)
            for line in reader:
                name = line['name']
                code = line['code']
                self.station_codes[name] = code

    def run(self):
        # 1.登陆
        self.login()
        # 2.查票
        self.search_ticket()
        # 3.确认乘客和车次信息
        self.confirm_data()

        # 登录
    def login(self):
        url = 'https://kyfw.12306.cn/otn/resources/login.html'
        driver.get(url)
        WebDriverWait(driver, 100).until(EC.url_changes(url))  # 在我们扫码登录后,页面会自动跳转,
        print('登陆成功')
        time.sleep(1)
   
    # 查票
    def search_ticket(self):
        driver.get('https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc')

        # 把出发地的编码填充进去
        fstation_input = driver.find_element_by_id('fromStation')
        fstation_code = self.station_codes[self.fstation]
        # type=hidden 这个标签是隐藏的,使用脚本方法填进去我们的出发点编码
        driver.execute_script("arguments[0].value='%s'" % fstation_code, fstation_input)

        # 目的地
        tstation_input = driver.find_element_by_id('toStation')
        tstation_code = self.station_codes[self.tstation]
        driver.execute_script("arguments[0].value='%s'" % tstation_code, tstation_input)

        # 时间
        date_input = driver.find_element_by_id('train_date')
        driver.execute_script("arguments[0].value='%s'" % self.date, 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")))
        train_trs = driver.find_elements_by_xpath("//tbody[@id='queryLeftTable']/tr[not(@datatran)]")
        # tr 标签有两个,我们只要第一个所以过滤有该属性的标签

        flag = False
        while True:
            for train in train_trs:
                infos = train.text.replace('\n', ' ').split(' ')
                number = infos[0]  # 车次名字
                if number in self.trains:  # 还有这种用法啊。。。检测这个我们是否要做这个车
                    for seat_type in self.trains[number]:  # 坐席
                        # 一等座
                        if seat_type == "M":
                            count = infos[8]
                            if count.isdigit() or count == '有':
                                flag = True
                                break  # 买一张票就行。。。。
                        # 二等座
                        elif seat_type == "O":
                            count = infos[9]
                            if count.isdigit() or count == '有':
                                flag = True
                                break
                if flag:
                    self.select_number = number  # 我们选择的车次,由于以后还会使也保存到初始变量中吧
                    order_btn = train.find_element_by_xpath('.//a[@class="btn72"]')
                    # 不用driver搜索全局了,用找到的子标签就好
                    order_btn.click()  # 点击预定。。。。
                    return

    # 确定乘车人,席别然后订票就好
    def confirm_data(self):
        WebDriverWait(driver, 100).until(EC.url_contains('https://kyfw.12306.cn/otn/confirmPassenger/initDc'))
        # 跳转页面后,检测url是否匹配

        # 检查选择乘车人的那个按钮加载出来没有
        WebDriverWait(driver, 100).until(
            EC.presence_of_element_located((By.XPATH, '//ul[@id="normal_passenger_id"]/li/label')))
        label = driver.find_elements_by_xpath('//ul[@id="normal_passenger_id"]/li/label')
        for passenger in label:
            name = passenger.text
            if name in self.passengers:      # 判断名字是否在里面,如果有点击就行,可以选择多个
                if '学生' in name:     # 学生票会格外弹出一个框框。。。。
                    passenger.click()
                    WebDriverWait(driver, 1000).until(EC.element_to_be_clickable((By.ID, 'dialog_xsertcj_ok')))
                    student = driver.find_element_by_id('dialog_xsertcj_ok')
                    student.click()
                else:
                    passenger.click()

        # 确定席别,是一个表单元素
        seat_select = Select(driver.find_element_by_id('seatType_1'))
        seat_types = self.trains[self.select_number]  # 根据用户选择的车次,找到用户需要的席别
        for seat_type in seat_types:
            try:
                seat_select.select_by_value(seat_type)  # 万一某种席别没了可以换一个
            except NoSuchElementException:
                continue
            else:
                break
        # 等待提交按钮能被点击
        WebDriverWait(driver, 1000).until(EC.element_to_be_clickable((By.ID, 'submitOrder_id')))
        submit_btn = driver.find_element_by_id('submitOrder_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')))    # 等待这个按钮可点
        confrim_btn = driver.find_element_by_id('qr_submit_id')  # 提交订单按钮
        try:  # 有可能会出现一些bug,第一次不行,一直点直到所选元素不存在,然后报错
            while True:
                confrim_btn.click()

        except:
            pass
        print("恭喜!成功抢到请在30分钟内完成付款")


def main():
    spider = TrainSpider('北京西', '长沙', '2020-05-01', {'G71': ['O', 'M']}, ['姓名(学生)']) # 要按格式输入啊,,,
    spider.run()


if __name__ == '__main__':
    main()

当然,,我们这个辣鸡抢票是肯定抢不过那些专业的,,,,,,学习用,抢不到票别找我

其实是有些问题的:

  • 有时候登录上去后,在预定票时又会显示没有登录。。。。可能是操作太快???反正偶尔会出现这样的问题,所以在登陆函数后加一个sleep 可以有效解决问题,,但是抢票程序啊,,,,hhhhhhh
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值