需求:用12306进行买票

第一步 登陆

  • 浏览器闪退如何解决
  • 显示等待页面跳转及页面加载

第二步 车次及余票查询

  • 由个人详情页面跳转车次界面
  • 先要获取所有的站点以及对应的编号–>把数数据存到字典当中 key name value code
  • 输入出发地 输入目的地 输入出发日期
    • 1 定位input标签
    • 2 获取编号
    • 3 driver.excute_script()方法来设置隐藏标签 code设置到value里面
    • 4 定位查询按钮 点击查询 出现车次列表

第三步 解析车次列表

  • 显式等待车次列表

  • 车次列表分析 tbody标签下面的 tr标签 过滤没有车次信息的tr标签 xpath (not )

  • 替换 拼接的方式把车次信息的数据放到了一个列表里面

  • init方法里面初始化了一个用户的车次 先获得了这个车次 做了一个判断 判断这个数据在我们初始

    化信息里面

  • 然后进行 我们想要买的车次的数据解析

第四步 确认乘客信息

  • 显式等待乘客信息页面

  • 显示等待是否乘客标签加载出来了

  • init 方法里面 初始化了乘客信息 [ xxx ,xxx]

  • 确定席位 select标签 Select类 下标 value 操作下拉菜单

  • 二等座如果没有了 NoSuchElementException try catch 点击提交按钮

    • 最终的确认信息

      • 等待这个确认菜单加载出来

      • 定位确定按钮 提交订单 就会在12306后台生成一个订单

      • 有可能会点击不到这个确定按钮 可以定义一个循环来不断点击 直到它抛出异常。就证

        明我们是点击到了 订单就提交成功了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import requests
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import csv
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import ElementNotVisibleException
#为什么出现闪退? 在这个程序中我们的driver会随着类的销毁而销毁
driver = webdriver.Chrome()
class TrainSpider():
login_url = 'https://kyfw.12306.cn/otn/resources/login.html' #登陆
personal_url = 'https://kyfw.12306.cn/otn/view/index.html' #个人信息
Ticket_url = 'https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc'#买票页面
confirm_url = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc' #订购界面
def __init__(self,fsta,tosta,tdata,trains,passengers):
'''

:param fsta: 出发地
:param tosta: 目的地
:param tdata: 日期
:param trains: 车次及席位
:param passengers: 乘客信息
'''
self.fsta = fsta
self.tosta = tosta
self.data = tdata
self.trains = trains
# self.driver = webdriver.Chrome()
self.passengers = passengers
self.selected_number = None
self.station_code = {} #初始化站点和对应编号
self.init_station_code()

def init_station_code(self):
with open('person.csv', 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for i in reader:
name = i['name']
code = i['code']
self.station_code[name] = code
def login(self):
driver.get(self.login_url)
#显式等待
WebDriverWait(driver,1000).until(
EC.url_contains(self.personal_url)
)
print('登陆成功')
def Ticket(self):
driver.get(self.Ticket_url)
#设置出发地目的地 出发日期
# 出发地
from_station_input = driver.find_element_by_id('fromStation')
from_station_code = self.station_code[self.fsta]
# arguments[0]对应的是第一个参数 type = 'hidden' 向input标签里面添加 value也就是BJP等等
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_code[self.tosta]
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)
driver.execute_script('arguments[0].value="%s"' % self.data, train_date_input)
btn = driver.find_element_by_id('query_ticket') #找到查询按钮 出现车次列表
btn.click()
WebDriverWait(driver,1000).until(
EC.presence_of_element_located((By.XPATH,'//tbody[@id="queryLeftTable"]/tr')) #显式等待直到加载tbody标签
)
trs = driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr[not(@datatran)]') #找到车次信息tr标签 过滤没有数据的tr标签
is_searched = False
for tr in trs:
# print(tr.text) #tr是一个selenium对象
infos = tr.text.replace('\n',' ').split(' ') #替换并分割车次列表
# print(infos)
num = infos[0]
if num in self.trains: #判断车次
seat_types = self.trains[num]
for seat_type in seat_types:
if seat_type == 'O': # 判断二等座位
count = infos[9]
if count.isdigit() or count == '有': #count.isdigit() 判断数字 或者有
is_searched = True
break
elif seat_type == 'M': #判断一等座位
count = infos[8]
if count.isdigit() or count == '有': # count.isdigit() 判断数字 或者有
is_searched = True
break
if is_searched:
self.selected_number = num #把确定好的席位传进来
order_btn = tr.find_element_by_xpath('.//a[@class="btn72"]')
order_btn.click()
break
def confrim(self):
WebDriverWait(driver,1000).until(
EC.url_contains(self.confirm_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')) #Select处理下拉菜单
seat_types = self.trains[self.selected_number]
for set_type in seat_types:
try: #解决无座问题 无下标索引值
seat_select.select_by_value(set_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_element_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.Ticket()
#3 确认乘客及席位
self.confrim()

def main():
#实例化对象
spider = TrainSpider('北京','长沙','2020-11-09',{'G485':['O','M'],},['XXX']) #二等座代号O 一等座代号M XXX练习时间可以用人名代替进行网页操作
spider.run()

if __name__ == '__main__':
main()

person.csv如下,如果知道其他站点代码 可以添加

1
2
3
4
5
name,code

北京,BJP

长沙,CSQ