1. 程式人生 > 其它 >12306預售車票 時間是2019年的哈 (記筆記)

12306預售車票 時間是2019年的哈 (記筆記)

技術標籤:pythonselenium

先說明一下哈,這個是從視訊上面我搬運的哈,視訊時間2019的,程式碼應該沒用
我只是單純的做筆記哈,寫一哈自己的感受哈

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.select import Select from selenium.common.exceptions import NoSuchElementException,ElementNotVisibleException #這是匯入一個異常哦 import csv driver=webdriver.Chrome() #將driver 設定為全域性變數 是因為 如果放在裡面 driver會隨著 物件的銷燬 而 被銷燬 class TrainSpider(object): login_url='登陸介面url' #定義在這裡 可以隨時 改變 url
presonal_url='這裡是登陸後跳轉的url 來判斷是否登陸成功' left_ticket_url='車次餘票url' confirm_passengner_url='確認乘客頁面的url' def __init__(self,from_station,to_station,train_date,trains,passengers): ''' :param from_station: 起始站 :param to_station: 目的站 :param train_date: 出發目標 :param trains: 需要購買車次 是一個字典 傳入例項:{'G529':['M','O'],'G403':{'M','O'}} :param passengers: 乘客的姓名 是一個列表 傳入例項: ['乘客名','乘客名','乘客名',] '''
self.from_station=from_station self.to_station=to_station self.train_date=train_date self.trains=trains self.passengers=passengers #將 傳過來的 變數 儲存在物件上 self.selected_seat=None self.selected_number=None #自己定義類中全域性變數 定義了 車號 和 席位 #self.driver=webdriver.Chrome() 放在裡面可以方便 輸出 有聯想 self.station_codes={} #定義(在外面而非 函式裡裡面) 變數 因為 車票 查詢 需要 self.init_station_code() #初始化站點所對應的代號 一開始自動執行函式 def init_station_code(self): #這個是得到站點的代號 為了輸入車票的起始點 with open('z stations.csv', 'r', encoding='utf-8') as fp: reader = csv.DictReader(fp) for line in reader: name = line['name'] code = line['code'] self.station_codes[name] = code def login(self): driver.get(self.login_url) #等待url 是否變為個人中心的url 來判斷 是否登陸成功 (設定顯示等待) WebDriverWait(driver,1000).until( #判斷條件 #EC.url_to_be(self.presonal_url) 變成這個url EC.url_contains(self.presonal_url) #包含這個url ) print('登陸成功!') def search_left_ticket(self): driver.get(self.left_ticket_url) #1.起始站代號設定 from_station_input = driver.find_element_by_id("fromStation") from_station_code=self.station_codes[self.from_station] '''self.station_codes[name] = code 因為這個 所以可以 返回 地點 代號''' driver.execute_script(f"arguments[0].value='{from_station_code}'" , from_station_input) #設定值到框框 #這種josnscript 設定值 一切情況 都 適用 '''因為type 是 hidden 被隱藏 所以需要採用josnscript程式碼來實現 arguments 代表 你給函式 傳的引數 是一個列表 "arguments[0].value='%s'" % from_code 是 json程式碼 from_station_input 傳的引數 如果有其他的引數 都 放在 arguments中''' #2.終點站代號設定 to_station_input = driver.find_element_by_id("toStation") to_station_code = self.station_codes[self.to_station] driver.execute_script(f"arguments[0].value='{to_station_code}'", to_station_input) #3.設定時間 train_date_input = driver.find_element_by_id("train_date") driver.execute_script(f'arguments[0].value={self.train_date}',train_date_input) #4.執行查詢操作 search_btn=driver.find_element_by_id('query_ticket') search_btn.click() #5.解析車次資訊 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(@datatran)]') #tr[not(@datatran)] 可以排除 含有 datatran 條件的 tr is_searched=False while True: #這個 死迴圈 是為了多次查詢 因為有些票時間沒到 還在準備預售 之前不加這個 就只查詢一次就沒了 for train_tr in train_trs: #print(train_tr.text) infos=train_tr.text.repalce('\n',' ').split(' ') #print(infos) number=infos[0] if number in self.trains: #判斷key(車號)是否在 字典 trains seat_types=self.trains[number] #如果有key(車號) 獲得車號需要的 seat_types for seat_type in seat_types: #遍歷這個車號的所有 資訊 #是否有二等座 if seat_type == 'O': #遍歷是否有 座位為二等座的 就可以進行下面的判斷二等座是否有 count=infos[9] if count.isdigit() or count == '有': is_searched=True break #是否有一等座 elif seat_type == 'M': count=infos[8] if count.isdigit() or count == '有': 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() return def confirm_passengers(self): #1.判斷是否變為確認乘客的url頁面 和 等待 確認購買乘客資訊的出現 WebDriverWait(driver,1000).until( EC.url_contains(self.confirm_passengner_url) ) #先等待乘客標籤顯示出來 WebDriverWait(driver,1000).until( EC.presence_of_element_located((By.XPATH,'//ul[@id="normal_passenger_id"]/li/label')) ) #2.確認需要購買車票的乘客 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() #3.確認需要購買的席位資訊 seat_select=Select(driver.find_element_by_id('seatType_1')) seat_types=self.trains[self.selected_number] #是一個列表 '''self.trains[self.selected_number] 因為傳過來的trains 是一個字典 所以可以通過key索引''' for seat_type in seat_types: try: self.selected_seat =seat_type seat_select.select_by_value(seat_type) except NoSuchElementException: #捕捉異常 continue #continue 就是 下次迴圈下一個座次 else: break #如果第一次就找到啦 就退出迴圈 #等待 提交訂單按鈕可以被點選 WebDriverWait(driver,1000).until( EC.element_to_be_clickable((By.ID,'submintOrder_id')) ) submit_btn=driver.find_element_by_id('submintOrder_id') 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")) ) submit_btn=driver.find_element_by_id("qr_submit_id") #submit_btn.click() #有可能 點選一次並不會出來 所以採用下面的 暴力迴圈點選 while submit_btn: try: submit_btn.click() submit_btn = driver.find_element_by_id("qr_submit_id") except ElementNotVisibleException: # 會報這個錯 ElementNotVisibleException 說明頁面已經換了 即代表成功了 就可以退出迴圈 break print(f"恭喜!成功搶{self.selected_number}次列車{self.selected_seat}席位,請在30分鐘內完成付款!" ) def run(self): # 一切相關的就放在這 相當於總控制者 #1.登入 () 定義一個 函式一個 self.login() #2.車次餘票查詢 self.search_left_ticket() #3.確認乘客和車次資訊 self.confirm_passengers() def main(): # 9:商務座,M:一等座,O:二等座,3:硬臥,4:軟臥,1:硬座 from_station=input('請輸入出發地:') to_station=input('請輸入目的地:') train_date=str(input('請輸入出發時間(請按照如下格式輸入時間: 2020-13-14):')) train_number=input('你準備乘坐的車號(車號例項:G520):') train_seat=input ("請輸入座位級別(輸入例項:m o):").split() train={train_number:train_seat} passenger_names=input ("輸入名字(輸入例項:小明 小紅):").split() spider=TrainSpider(from_station,to_station,train_date,train,passenger_names) spider.run() if __name__ == '__main__': main()
  1. 這裡對 類中的 引數的傳入和設定 有了新的 理解 之前沒麼怎麼使用過類
    對引數的 傳入 和 設定

傳入 我自己的理解 就相當於 c語言中 對函式傳值一樣那種 只不過在類中使用 需要初始化(self.from_station=from_station我也不知道這個是不是叫初始化)

設定嘛 就是平時一樣的 就使用的時候 加個self

   def __init__(self,from_station,to_station,train_date,trains,passengers):
        '''

        :param from_station: 起始站
        :param to_station: 目的站
        :param train_date: 出發目標
        :param trains: 需要購買車次    是一個字典 傳入例項:{'G529':['M','O'],'G403':{'M','O'}}
        :param passengers: 乘客的姓名   是一個列表 傳入例項: ['乘客名','乘客名','乘客名',]
        '''
        self.from_station=from_station
        self.to_station=to_station
        self.train_date=train_date
        self.trains=trains
        self.passengers=passengers       #將 傳過來的 變數 儲存在物件上
        self.selected_seat=None
        self.selected_number=None        #自己定義類中全域性變數   定義了 車號 和 席位

        #self.driver=webdriver.Chrome()  放在裡面可以方便 輸出 有聯想

        self.station_codes={}       #定義(在外面而非 函式裡裡面) 變數  因為  車票 查詢 需要
        self.init_station_code()   #初始化站點所對應的代號     一開始自動執行函式

對於 driver.execute_script(f"arguments[0].value='{from_station_code}'" , from_station_input) 這個認識

driver.execute_script(f"arguments[0].value='{from_station_code}'" , from_station_input)  #設定值到框框
        #這種josnscript 設定值   一切情況     都   適用
        '''因為type 是 hidden 被隱藏   所以需要採用josnscript程式碼來實現
        arguments  代表   你給函式   傳的引數    是一個列表
        "arguments[0].value='%s'" % from_code 是 json程式碼
        from_station_input 傳的引數   如果有其他的引數 都   放在 arguments中'''

3.以及 處處都需要顯示等待的條件 思維

 #1.判斷是否變為確認乘客的url頁面  和 等待 確認購買乘客資訊的出現
        WebDriverWait(driver,1000).until(
            EC.url_contains(self.confirm_passengner_url)
        )
           #先等待乘客標籤顯示出來
        WebDriverWait(driver,1000).until(
            EC.presence_of_element_located((By.XPATH,'//ul[@id="normal_passenger_id"]/li/label'))
        )

4.以及輸出列表的方式

passenger_names=input ("輸入名字(輸入例項:小明 小紅):").split()