前言
不知道小伙伴们有没有过这样得经历,当自己想从学校回家或者想去往某地的时候发现自己想要得车票已经卖光了。我们就只能等待有没有加车,或者是使用抢票软件进行抢票,然后请求请朋好友加速,直到有多余的票出现了,完成抢票直接完成抢票,然后你只需要在规定的时间内完成付款就OK了。今天我们就要使用selenium+chrome完成这一项目。
首先我们找到目标网址,然后扫码进入,我们会发现界面。(如下)
首先我们需要输入的是出发地信息,然后输入目的地信息,然后在输入出发日期,然后我们再点击查询。我们手动点击之后会发现呈现下方的信息:
到达这个步骤之后呢,我们选择车次,然后看自己选择座位信息,如图我们可以看到,如果显示的是数字或者是有这就说明了对应的座位有座,比如图中的D111我们选择二等座,就会显示有。然后我们直接点击预定。然后我们看结果。
这里我们就会看到乘客信息,然后我们点击需要购票的用户,然后信息就会自动填充到上图的空格中,然后我们直接点击提交订单即可。然后会出现下方界面
这里我们可以选具体座位,如果不需要,则直接点击确认。然后下一步直接点击支付就可以了。
我们在第一步输入出发地的时候在运行的时候发现如果输入纯文字文本会报错,经过查询我们了解到对于我们选择的过程中其实后台不是按照文字文本来查找的,而是按照地址代码来查找比如
以上我们简单的罗列一部分代码,目的就是告诉大家我们在查找的过程中不是输入的文本信息,而是输入的地址代码。
因为网页跳转然后继续执行程序是非常快的,有的时候新的页面还没有出现呢,你就要执行新的操作,那么计算机根本再当前页面中找不到你想要执行的操作,所以我们在进行页面的更换的时候一定要加入等待,加入条件,比如条件是页面出现了,然后我们才可以执行操作。
我使用的python3的版本,由于python3已经淘汰掉了一些python2版本的一些语法,所以我们在写代码的时候要对其进行更改。比如
from_station_input=driver.find_element_by_id("fromStation")
#上方的语法就已经被淘汰了,应该替换成下方代码。
from_station_input=driver.find_element(By.ID,"fromStation")
首先selenium库一定要有,显示等待,时间库(time),等待条件,By,csv操作文件库,Select库
import time
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 csv
from selenium.webdriver.support.select import Select
from selenium.common.exceptions import NoSuchElementException,ElementNotVisibleException
以上为本项目所需要的所有库
我们需要有对出发地目的地的代码导入的相应函数。需要打开文件,然后转化为字典格式,csv.DictReader相当于就是把文字内容作为第一行的key,把文本对应的代码作为value。然后直接把name,转化为代码形式。
def opeate_csv_code(self):
with open("stations.csv", 'r', encoding='utf-8') as fp:
readers = csv.DictReader(fp)
for reader in readers:
name = reader['name']
code = reader['code']
self.train_station[name]=code
具体我将代码注释标注在相应的后方
def search_left_ticket(self):
driver.get(self.purchase_url)
from_code=self.train_station[self.from_station]#通过opeate_csv_code函数直接将出发地转化为相应地址代号
to_code=self.train_station[self.to_station]#同上
from_station_input=driver.find_element(By.ID,"fromStation")
#找到出发地的源码对应
to_station_input=driver.find_element(By.ID,'toStation')
#找到目标地的源码对应
train_date_input=driver.find_element(By.ID,'train_date')
#找到对应日期的源码对应
driver.execute_script("arguments[0].value='%s'" % from_code, from_station_input)#对from_station_input进行输入from_code操作
driver.execute_script("arguments[0].value='%s'" % to_code, to_station_input)#同上
driver.execute_script("arguments[0].value='%s'" % self.train_data,train_date_input)#原理同上
queryBtn = driver.find_element(By.ID,"query_ticket")#找到查询按钮
driver.execute_script("arguments[0].click();", queryBtn)
#对查询按钮进行点击操作语法等于queryBtn.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(@style)]")#找到可以乘坐的相应车次
is_searched = False#is_searched作为是否点击预定的判定条件
for train_tr in train_trs:
infos=train_tr.text.replace("\n"," ").split(" ")
# 9:商务座,M:一等座,O:二等座,3:硬卧,4:软卧,1:硬座
order_btn=driver.find_element(By.XPATH,".//a[@class='btn72']")#预定按钮
number=infos[0]#列车车号
if number in self.trains:#self.trains对应主函数中的想要做的车次
for seat_type in self.trains[number]:#想要做的车次中的什么类型的座位,进行遍历
if seat_type == "O":
count=infos[8]
if count.isdigit() or count =="有":
is_searched = True
break#判断是否对应的O有票
elif seat_type == "3":
count=infos[13]
if count.isdigit() or count =="有":
is_searched = True
break
if is_searched:
self.current_number=number # 车列号
order_btn.click()
break#如果有则点击
def confirm_passenger(self):
WebDriverWait(driver,1000).until(
EC.url_contains(self.submit_url)
)#页面信息
# 等待乘客信息元素被加载进来
WebDriverWait(driver, 1000).until(
EC.presence_of_element_located((By.XPATH, "//ul[@id='normal_passenger_id']/li"))
)
# 等待席位元素被加载进来
WebDriverWait(driver, 1000).until(
EC.presence_of_element_located((By.XPATH, "//select[@id='seatType_1']/option"))
)#选座位信息被加载进来
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.passenges:
passenger_label.click()#完成点击
seat_select=Select(driver.find_element(By.ID,"seatType_1"))#选座
for seat_type in self.trains[self.current_number]:
try:
seat_select.select_by_value(seat_type)
self.current_seat_type = seat_type
except NoSuchElementException:
continue
else:
break
WebDriverWait(driver,1000).until(
EC.element_to_be_clickable((By.ID,"submitOrder_id"))
)#等待提交按钮可以被点击
final_submit_btn=driver.find_element(By.ID,"submitOrder_id")
final_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"))
)#确定按钮可以被点击
confirm_submit_btn = driver.find_element(By.ID,"qr_submit_id")
while confirm_submit_btn:
try:
confirm_submit_btn.click()
time.sleep(5)
confirm_submit_btn = driver.find_element(By.ID,"qr_submit_id")
except ElementNotVisibleException:
break#每隔5秒点击一次
print("恭喜!成功抢到【%s】次列车【%s】席位,请在30分钟内完成付款!"%(self.current_number,self.current_seat_type))
time.sleep(100)
def run(self):
self.login_page()
self.search_left_ticket()
self.confirm_passenger()
def main():
spider=TrainSpider("沈阳","长春","2022-04-20",{"G1237":["3","O","M"]},["马云海"])
spider.run()