1、申 请 I D:xiaopacai2
2、个人邮箱:464757237@qq.com
3、原创技术文章:利用python结合selenium编写12306自动化抢票程序
代码简介:
- selenium结合谷歌驱动登陆12306火车票订购网站,其中验证等待手动输入
- 获取输入的出发地-目的地信息并查询车票
- pandas保存返回的车次以及座位信息
- 选择乘车人以及车次,座次,如果有票,提交订单
- 如果没有,每5s刷新一次车次信息,直到抢到对应的车票
代码如下:
[Python] 纯文本查看 复制代码 # -*- coding: utf-8 -*-
"""
Created on Sun Jan 30 19:45:18 2022
@author: Yuan
"""
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
import pandas as pd
import time
class get_tickets(object):
def __init__(self):
self.login_url = 'https://kyfw.12306.cn/otn/resources/login.html'
self.init_url = 'https://kyfw.12306.cn/otn/view/index.html'
self.search_url = 'https://kyfw.12306.cn/otn/leftTicket/init'
self.driver = webdriver.Chrome()
self.options = webdriver.ChromeOptions()
self.script = 'Object.defineProperty(navigator,"webdriver",{get:()=>undefined,});'
self.data_frame = pd.DataFrame(columns = ['车次','站点','时间','历时','商务座','一等座','二等座','高级软卧','一等软卧','动卧','硬卧','软座','硬座','无座','其他'])
# 更换头部
self.user_agent = (
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36'
)
def _login(self):
self.driver.maximize_window()
self.options.add_argument('user-agent=%s'%self.user_agent)
self.driver.get(self.login_url)
self.driver.execute_script(self.script)
WebDriverWait(self.driver , 1000).until(
EC.url_to_be(self.init_url)
)
print('登陆成功!!')
def _wait_input(self):
self.from_station = input('出发地:')
self.to_station = input('目的地:')
#标准时间格式:yyyy-mm-dd
self.depart_time = input('出发日(注意格式:yyyy-mm-dd):')
#self.passengers = input('乘客姓名(如果有多个用,隔开)').split(',')
#self.trains = input('输入列车车次(有多个用,隔开):').split(',')
def _get_pos(self , seat_type):
pos = None
for row_num,rows in self.data_frame.iterrows():
if self.target_train.upper() in rows[0].upper() and rows[seat_type] != '无' and rows[seat_type] != '候补' and rows[seat_type] != '--':
print('当前是否有票:',rows[seat_type])
pos = str(2 * (row_num + 1) - 1)
return pos
def _get_data(self):
#清空数据
self.data_frame.drop(self.data_frame.index,inplace=True)
#获取可预订数据
td1 = self.driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr/td[1]/div/div[@class="train"]/div')
td2 = self.driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr/td[1]/div/div[@class="cdz"]')
td3 = self.driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr/td[1]/div/div[@class="cds"]')
td4 = self.driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr/td[1]/div/div[@class="ls"]')
td5 = self.driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr/td[2]')
td6 = self.driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr/td[3]')
td7 = self.driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr/td[4]')
td8 = self.driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr/td[5]')
td9 = self.driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr/td[6]')
td10 = self.driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr/td[7]')
td11 = self.driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr/td[8]')
td12 = self.driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr/td[9]')
td13 = self.driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr/td[10]')
td14 = self.driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr/td[11]')
td15 = self.driver.find_elements_by_xpath('//tbody[@id="queryLeftTable"]/tr/td[12]')
for td1,td2,td3,td4,td5,td6,td7,td8,td9,td10,td11,td12,td13,td14,td15 in zip(td1,td2,td3,td4,td5,td6,td7,td8,td9,td10,td11,td12,td13,td14,td15):
list_tr = [td1.text.replace('\n','-'),td2.text.replace('\n','-'),td3.text.replace('\n','-'),td4.text.replace('\n','-'),td5.text,td6.text,td7.text,td8.text,td9.text,td10.text,td11.text,td12.text,td13.text,td14.text,td15.text]
index_size = self.data_frame.index.size
self.data_frame.loc[index_size] = list_tr
pd.set_option('display.max_columns', None) #设置显示的最大列数参数
pd.set_option('display.max_rows', None) #设置显示的最大的行数参数
pd.set_option('display.width',100) #设置显示的宽度
#查询网页元素是否存在
def isElementExist(self, value_type , element):
flag=True
browser=self.driver
try:
if value_type == 'id':
browser.find_element_by_id(element)
elif value_type == 'xpath':
browser.find_element_by_xpath(element)
return flag
except:
flag=False
return flag
def _clickWarningWindow(self):
if self.isElementExist('id','qd_closeDefaultWarningWindowDialog_id' ):
self.driver.find_element_by_id('qd_closeDefaultWarningWindowDialog_id').click()
def _order_tickets(self):
self.driver.get(self.search_url)
self._clickWarningWindow()
#等待出发地输入正确
WebDriverWait(self.driver , 1000).until(
EC.text_to_be_present_in_element_value((By.ID , 'fromStationText') , self.from_station)
)
#等待目的地输入正确
WebDriverWait(self.driver , 1000).until(
EC.text_to_be_present_in_element_value((By.ID , 'toStationText') , self.to_station)
)
#等待出发日期正确
WebDriverWait(self.driver , 1000).until(
EC.text_to_be_present_in_element_value((By.ID , 'train_date') , self.depart_time)
)
#等待查询按钮是否能够呗点击
WebDriverWait(self.driver , 1000).until(
EC.element_to_be_clickable(('id' , 'query_ticket'))
)
searchBtn = self.driver.find_element_by_id('query_ticket')
searchBtn.click()
#print('====正在打印车次信息====')
time.sleep(5)
self._get_data()
print(self.data_frame)
self.target_train = input('请输入需要选择的车次:')
seat_type = input('请输入需要选择的作为类别:')
#print(self._get_pos(seat_type))
#self.driver.refresh()
#如果没有找到车次,循环获取订单页面
while self._get_pos(seat_type) is None:
WebDriverWait(self.driver , 1000).until(
EC.element_to_be_clickable(('id' , 'query_ticket'))
)
searchBtn = self.driver.find_element_by_id('query_ticket')
searchBtn.click()
self._clickWarningWindow()
time.sleep(10)
self._get_data()
print(self.data_frame)
#点击对应车次预定按钮
self.driver.find_element_by_xpath('//tbody[@id="queryLeftTable"]/tr[' + self._get_pos(seat_type) +']/td[13]/a[@class="btn72"]').click()
#车次时间较近
self._clickWarningWindow()
#等待页面跳转到订单界面
time.sleep(5)
#输入乘车人
Passenger = input('请输入乘车人姓名,如有多个按逗号隔开:').split(',')
li_list = self.driver.find_elements_by_xpath('//*[@id="normal_passenger_id"]/li')
for index , value in enumerate(li_list):
if value.text in Passenger:
self.driver.find_element_by_xpath('//*[@id="normal_passenger_id"]/li['+ str(index + 1) +']/label').click()
self._clickWarningWindow()
#提交订单
self.driver.find_element_by_id('submitOrder_id').click()
time.sleep(5)
#选择座位位置//*[@id="1F"]
''' 鼠标悬停
element = self.driver.find_element_by_xpath('//*[@id="'+ seat_num.upper() +'"]')
ActionChains(self.driver).move_to_element(element).perform()
'''
seat_list = input('请输入需要选择的座位号:').split(',')
if seat_list != []:
for seat_num in seat_list:
print(seat_num.upper())
element = self.driver.find_element_by_xpath('//*[@id="'+ seat_num.upper() +'"]')
self.driver.execute_script("arguments[0].click", element)
#self.driver.find_element_by_id('qr_submit_id').click()
def run(self):
self._wait_input()
self._login()
self._order_tickets()
if __name__ == '__main__':
spider = get_tickets()
spider.run()
#spider.driver.quit() |