异常处理
所有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