selenium实现12306购票
初衷: 练习一下selenium的知识点 一定可以的
第一步 登录
- 不要把驱动写到我们的类里面。因为这样会随着类的销毁驱动也会消失,我们要放到全局变量里面
- 登录成功之后 做了一个显示等待 条件是 个人中心的页面
第二步 车次以及余票查询
## https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc
- 由个人详情页面跳转到了车次查询界面
- 获取所有的站点以及对应的编号 --> 保存到了一个字典当中 key name value code
- 要在 出发地 目的地 出发日期 这些 input标签里面进行设置
。1 定位input标签
。2 获取编号
。3 execute_scrip()方法来设置隐藏标签
driver.execute_script('arguments[0].value="%s"' % self.train_data,
train_data_input
- 点击查询 出现车次列表
第三步 解析车次列表
显示等待车次列表(条件 这些tr标签加载完成)
车次列表分析 tbody标签下面的tr标签 过滤车次信息 把 [not(@datatran)]
替换并拼接的方式把车次信息放到一个列表当中
init方法里面初始化了一个用户车次 先获得车次 做判断 这个数据是在我们的车次列表
确定乘坐的席位 点击这个席位的预定按钮 xpath
确认乘客信息的界面
第四步 确认乘客信息和席位
-
显示等待 条件是判断是否确认乘客信息
-
补充 显示等待 乘客标签有没有加载出来 label ( input 标签选不中)
-
init 方法里面进行初始化了乘客信息 [‘xxx’,‘xxxx’]
-
人对应了一个它的席位 name —> value
-
席位是select标签 下标/ value
-
二等座正好没有了 NoSuchElementException try catch处理
。最终的提交订单
。等待弹框的页面加载出来
。定位确定按钮 提交订单 就会生成订单 -
有可能点击不住那个提交订单的按钮 (无限循环去点击这个按钮 直到点击成功 出现那个提示为止
完整代码
import csv
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, ElementNotInteractableException
driver = webdriver.Chrome()
class TrainSpider():
login_url = 'https://kyfw.12306.cn/otn/resources/login.html' # 登录的界面
person_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' # 确认乘客信息的地址
def __init__(self, from_station, to_station, train_data,trains,passengers):
'''
:param from_station: 出发地
:param to_station: 目的地
:param train_data: 出发日期
:param trains: 需要购买的车次以及车次所对应的席位 {'G1972':['M','O']}
:param passengers: 乘车人姓名 他是一个列表['张三','李四']
'''
self.from_station = from_station
self.to_station = to_station
self.train_data = train_data
self.trains=trains
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 f1:
reader = csv.DictReader(f1)
for line in reader:
name = line['name']
code = line['code']
self.station_codes[name]=code
def login(self): # 登录模块
driver.get(self.login_url)
WebDriverWait(driver,1000).until(
EC.url_contains(self.person_url) # 包含登录后的url 进行显示等待
)
print("登录成功!")
def search_left_ticket(self): # 2.车次以及余票查询
driver.get(self.left_ticket_url) #加载余票查询的界面
#出发地
from_station_input=driver.find_element_by_id("fromStation")
from_station_code=self.station_codes[self.from_station]
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_data_input=driver.find_element_by_id('train_date')
driver.execute_script('arguments[0].value="%s"' % self.train_data, train_data_input)
#执行查询操作
trun_btn=driver.find_element_by_id('qd_closeDefaultWarningWindowDialog_id')
trun_btn.click()
serach_btn=driver.find_element_by_id('query_ticket')
serach_btn.click()
#解析车次信息
WebDriverWait(driver,1000).until(
EC.presence_of_element_located((By.XPATH,'//tbody[@id="queryLeftTable"]/tr')) #加载一个元素出来结束显示等待
)
#获取tr标签 把含有datatran的标签过滤掉
train_trs=driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr[not(@datatran)]')
is_searched=False
for train_tr in train_trs:
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':
#二等座
count=infos[9]
if count=="有" or count.isdigit():
is_searched=True
break
elif seat_type=='M':
#一等座
count = infos[8]
if count == "有" or count.isdigit():
is_searched = True
break
if is_searched:
self.selected_number=number
#点击预订
order_btn=train_tr.find_element_by_xpath('.//a[@class="btn72"]')
order_btn.click()
break
def confirm_passengers(self):
WebDriverWait(driver,1000).until(
EC.url_contains(self.confirm_passengers_url)
)
#如果出现无法点击提交按钮
WebDriverWait(driver, 1000).until(
EC.presence_of_element_located((By.XPATH,'//ul[@id="normal_passenger_id"]/li/label'))
)
#确认需要购买车票的乘客
passenger_labels=driver.find_elements_by_xpath('//ul[@id="normal_passenger_id"]/li/label')
for passenger_label in passenger_labels:
name=passenger_label.text
if name in self.passengers:
passenger_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
#提交订单
subm_btn=driver.find_element_by_id("submitOrder_id")
subm_btn.click()
WebDriverWait(driver,1000).until(
EC.presence_of_element_located((By.CLASS_NAME,'dhtmlx_window_active'))
)
#确定按钮
btn=driver.find_element_by_id('qr_submit_id')
while btn:
try:
btn.click()
btn = driver.find_element_by_id('qr_submit_id')
except ElementNotInteractableException:
break
def run(self):
# 1.登录
self.login()
#2.车次以及余票查询
self.search_left_ticket()
#3.确认乘客信息与车次信息
self.confirm_passengers()
def main():
spider = TrainSpider('兰州', '上海', '2021-01-13',{'G1972':['O','M']},['龙悟选'])
spider.run()
if __name__ == '__main__':
main()