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()