current position:Home>Python queries 12306 tickets and uses selenium to buy tickets

Python queries 12306 tickets and uses selenium to buy tickets

2022-02-02 14:57:42 justtodowell

Tips : When the article is finished , Directories can be generated automatically , How to generate it, please refer to the help document on the right

List of articles



Preface

As the Spring Festival approaches , Buying tickets has become a big problem , So it becomes very interesting to write a simple ticket buying applet by yourself


Tips : The following is the main body of this article , The following cases can be used for reference


One 、 The overall architecture of the program

Before writing the program , We should first understand what we are doing in 12306 What kind of process should be carried out when buying tickets , After we check the tickets , If there are tickets , Then we'll log in , After successful login, you can buy tickets . The general flow chart is as follows :

With this flowchart , We can design some modules of our program


Two 、 Code writing


1.UI Design

adopt designer To design UI, Three are designed this time UI

 


2. Query module

The writing of query module needs to pay attention to , We use it requests When you get the address , There will be more 12306 Information to be submitted during ticket inspection

#12306 Ticket address 
tikes="https://kyfw.12306.cn/otn/leftTicket/query"
# Information to be submitted , Encapsulate with a dictionary 
query_params = {
    "leftTicketDTO.train_date": tran_date,
    "leftTicketDTO.from_station": from_station,
    "leftTicketDTO.to_station": to_station,
    "purpose_codes": purpose_code
}
 If you still can't get the data , Then we can add a head , Disguise yourself as a browser ( I use Chrome browser )
headrs = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36',
            'Cookie': '_uab_collina=163689535304202042315973; JSESSIONID=C89EB44A4BDC97B8EB9A4E7955FCA94F; route=9036359bb8a8a461c164a04f8f50b252; BIGipServerotn=2280128778.24610.0000; RAIL_EXPIRATION=1637210970420; RAIL_DEVICEID=FBb96qPa1M1EqO-Nj9rP-_kseasv05MVTorGDOCS6EBOT-Dei-zT7_dxLz5I-ktyJJ_ZQeD8pa4BniUQSmBh2bNykBQh_ATcwDA0JEB3yQpJ59wbHORgQ9Y-rzNJoJnVhj2mGRtpgQJno_SPSGDhLreIOTfiZ5mc; guidesStatus=off; highContrastMode=defaltMode; cursorStatus=off; _jc_save_fromStation=%u5317%u4EAC%2CBJP; _jc_save_toStation=%u5929%u6D25%2CTJP; _jc_save_fromDate=2021-11-14; _jc_save_toDate=2021-11-14; _jc_save_wfdc_flag=dc'}

  Get is json data , So we need to parse the data

resp = requests.get(API.QUERY_tikes, params=query_params, headers=headrs)

resp.encoding = resp.apparent_encoding

The next step is to simply process the data

items = resp.json()['data']['result']

        train_dicts = []
        for item in items:
            trainDict = {}

            trainInfo = item.split('|')
            if trainInfo[11] == 'Y':  #  Can I book 
                trainDict['secret_str'] = trainInfo[0]  #  Train number ciphertext string ( Use... When placing an order )
                trainDict['train_num'] = trainInfo[2]  #  Train number  24000000Z30L
                trainDict['train_name'] = trainInfo[3]  #  The name of the train , Such as D352
                trainDict['from_station_code'] = trainInfo[6]  #  Departure telegraph code 
                trainDict['to_station_code'] = trainInfo[7]  #  Destination telegraph code 
                trainDict['from_station_name'] = code2station[trainInfo[6]]  #  Name of place of departure   Manual implementation   Beijing 
                trainDict['to_station_name'] = code2station[trainInfo[7]]  #  Name of destination   Manual implementation   Shanghai 
                trainDict['start_time'] = trainInfo[8]  #  Departure time 
                trainDict['arrive_time'] = trainInfo[9]  #  Arrival time 
                trainDict['total_time'] = trainInfo[10]  #  Total use time 
                trainDict['left_ticket'] = trainInfo[12]  #  Surplus ticket  wrlmtI6BmBd8izygoiCBbpr3%2B%2BGKdIk1SHpJdJ1f6w1p%2FhGF
                trainDict['train_date'] = trainInfo[13]  #  Train date  20190121
                trainDict['train_location'] = trainInfo[15]  # P4  Later use 
                trainDict["vip_soft_bed"] = trainInfo[21]  #  Advanced soft bed 
                trainDict['other_seat'] = trainInfo[22]  #  other 
                trainDict["soft_bed"] = trainInfo[23]  #  Soft sleeper 
                trainDict["no_seat"] = trainInfo[26]  #  No seat 
                trainDict["hard_bed"] = trainInfo[28]  #  Hard sleeper 
                trainDict['hard_seat'] = trainInfo[29]  #  Hard seat 
                trainDict["second_seat"] = trainInfo[30]  #  Second-class seat 
                trainDict["first_seat"] = trainInfo[31]  #  First class seat 
                trainDict["business_seat"] = trainInfo[32]  #  Business block 
                trainDict["move_bed"] = trainInfo[33]  #  Move and lie 

The query module basically ends here , Next is the ticket grabbing module

3. Ticket grabbing module

In the ticket grabbing module, add a train number if a certain seat type is selected , The query module will filter the data , The specific code is as follows :

                if seattype == None:
                    train_dicts.append(trainDict)
                else:
                    print(seattype)
                    key = config.seat_type_map_dic[seattype]
                    print(key)
                    print(trainDict[key])
                    if trainDict[key] == " Yes " or trainDict[key].isdigit():
                        train_dicts.append(trainDict)
                        print(trainDict)

Completed query code

    def que_titkes(cls, tran_date, from_station, to_station, purpose_code, seattype=None):
        code2station = APItool.get_all_stations_revers()

        query_params = {
            "leftTicketDTO.train_date": tran_date,
            "leftTicketDTO.from_station": from_station,
            "leftTicketDTO.to_station": to_station,
            "purpose_codes": purpose_code
        }
        headrs = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36',
            'Cookie': '_uab_collina=163689535304202042315973; JSESSIONID=C89EB44A4BDC97B8EB9A4E7955FCA94F; route=9036359bb8a8a461c164a04f8f50b252; BIGipServerotn=2280128778.24610.0000; RAIL_EXPIRATION=1637210970420; RAIL_DEVICEID=FBb96qPa1M1EqO-Nj9rP-_kseasv05MVTorGDOCS6EBOT-Dei-zT7_dxLz5I-ktyJJ_ZQeD8pa4BniUQSmBh2bNykBQh_ATcwDA0JEB3yQpJ59wbHORgQ9Y-rzNJoJnVhj2mGRtpgQJno_SPSGDhLreIOTfiZ5mc; guidesStatus=off; highContrastMode=defaltMode; cursorStatus=off; _jc_save_fromStation=%u5317%u4EAC%2CBJP; _jc_save_toStation=%u5929%u6D25%2CTJP; _jc_save_fromDate=2021-11-14; _jc_save_toDate=2021-11-14; _jc_save_wfdc_flag=dc'}

        resp = requests.get(API.QUERY_tikes, params=query_params, headers=headrs)

        resp.encoding = resp.apparent_encoding
        items = resp.json()['data']['result']

        train_dicts = []
        for item in items:
            trainDict = {}

            trainInfo = item.split('|')
            if trainInfo[11] == 'Y':  #  Can I book 
                trainDict['secret_str'] = trainInfo[0]  #  Train number ciphertext string ( Use... When placing an order )
                trainDict['train_num'] = trainInfo[2]  #  Train number  24000000Z30L
                trainDict['train_name'] = trainInfo[3]  #  The name of the train , Such as D352
                trainDict['from_station_code'] = trainInfo[6]  #  Departure telegraph code 
                trainDict['to_station_code'] = trainInfo[7]  #  Destination telegraph code 
                trainDict['from_station_name'] = code2station[trainInfo[6]]  #  Name of place of departure   Manual implementation   Beijing 
                trainDict['to_station_name'] = code2station[trainInfo[7]]  #  Name of destination   Manual implementation   Shanghai 
                trainDict['start_time'] = trainInfo[8]  #  Departure time 
                trainDict['arrive_time'] = trainInfo[9]  #  Arrival time 
                trainDict['total_time'] = trainInfo[10]  #  Total use time 
                trainDict['left_ticket'] = trainInfo[12]  #  Surplus ticket  wrlmtI6BmBd8izygoiCBbpr3%2B%2BGKdIk1SHpJdJ1f6w1p%2FhGF
                trainDict['train_date'] = trainInfo[13]  #  Train date  20190121
                trainDict['train_location'] = trainInfo[15]  # P4  Later use 
                trainDict["vip_soft_bed"] = trainInfo[21]  #  Advanced soft bed 
                trainDict['other_seat'] = trainInfo[22]  #  other 
                trainDict["soft_bed"] = trainInfo[23]  #  Soft sleeper 
                trainDict["no_seat"] = trainInfo[26]  #  No seat 
                trainDict["hard_bed"] = trainInfo[28]  #  Hard sleeper 
                trainDict['hard_seat'] = trainInfo[29]  #  Hard seat 
                trainDict["second_seat"] = trainInfo[30]  #  Second-class seat 
                trainDict["first_seat"] = trainInfo[31]  #  First class seat 
                trainDict["business_seat"] = trainInfo[32]  #  Business block 
                trainDict["move_bed"] = trainInfo[33]  #  Move and lie 
                if seattype == None:
                    train_dicts.append(trainDict)
                else:
                    print(seattype)
                    key = config.seat_type_map_dic[seattype]
                    print(key)
                    print(trainDict[key])
                    if trainDict[key] == " Yes " or trainDict[key].isdigit():
                        train_dicts.append(trainDict)
                        print(trainDict)

        return train_dicts

In the query module , I encapsulated the code into a class function , So in the ticket grabbing module , We set the timer , Just execute the query module regularly , After the query module is executed , Will judge the corresponding as data , If there are seats , Then you will enter a subsequent login interface , Enter your account and password , To get into selenium The web page automatically logs in and grabs tickets .

The following is the function of timer :

self.timer=QTimer(self)
self.timer.timeout.connect(self.buy_tikit)

Login module code :

    def checklogin(self):
        
        self.account = self.comboBox.currentText()
        self.password = self.password_le.text()
        self.cursor.execute(self.sql, (self.account, self.password))
        sel_qiang = selinu_qiang.Qiangpiao(self.from_station, self.to_station,         self.depart_time, self.train_num,
                                           self.passenger, self.account, self.password)
        sel_qiang.run()

4.selenium Web ticket

In this module, I refer to the following big man's blog

​​​​​​​  newest 12306 Ticket grabbing crawler _ Daniel's blog -CSDN Blog _12306 Reptiles automatically grab tickets

After simple modification and UI The ginseng , Realize the connection between multiple modules

The specific code is as follows :

import time
import datetime

from PyQt5.QtWidgets import QMessageBox
from selenium import webdriver
from selenium.webdriver.chrome.webdriver import WebDriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver import ChromeOptions
import Login_Pane
class Qiangpiao():
    def __init__(self,from_station,to_station,depart_time,train_num,passenger,username,password):
        self.login_url = 'https://kyfw.12306.cn/otn/resources/login.html'
        self.init_my_url = 'https://kyfw.12306.cn/otn/view/index.html'
        self.order_url = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
        self.train_num = train_num
        self.passenger = passenger
        self.userna=username
        self.password=password
        self.Login_ti=Login_Pane.LoginPane

        # Get current month 
        self.now_month = datetime.date.today().month
        print(self.now_month)



    def _login(self):
        option = ChromeOptions()
        option.add_experimental_option('excludeSwitches', ['enable-automation'])
        self.driver = webdriver.Chrome(options=option)
        self.driver.maximize_window()


        #  Use selenium Open the landing page 
        self.driver.get('https://kyfw.12306.cn/otn/resources/login.html')
        script = 'Object.defineProperty(navigator,"webdriver",{get:()=>undefined,});'
        self.driver.execute_script(script)
        self.driver.maximize_window()

        #  Google's display position of the verification code is misplaced when trying it on its own , So I wrote two more jump refresh operations 

        time.sleep(3)

        self.driver.find_element_by_xpath('//*[@id="J-userName"]').send_keys("19102870304")
        time.sleep(2)
        self.driver.find_element_by_xpath('//*[@id="J-password"]').send_keys("tlmm123")
        time.sleep(2)
        self.driver.find_element_by_xpath('//*[@id="J-login"]').click()
        time.sleep(3)

        #  Slider verification 
        span = self.driver.find_element_by_xpath('//*[@id="nc_1_n1z"]')
        time.sleep(1)
        action = ActionChains(self.driver)
        time.sleep(2)
        action.click_and_hold(span)
        action.drag_and_drop_by_offset(span, 300, 0).perform()
        time.sleep(5)

        # WebDriverWait(self.driver, 1000).until(EC.url_to_be(self.init_my_url))
        print(' Login successful !')

    def _pop_window(self):
        time.sleep(1)
        self.driver.find_element_by_xpath('//*[@class="dzp-confirm"]/div[2]/div[3]/a').click()

    def _enter_order_ticket(self):
        action = ActionChains(self.driver)
        element = self.driver.find_element_by_link_text(' ticket ')
        #  Move the mouse to  ' ticket '  The center point on the element 
        action.move_to_element(element).perform()
        #  Click on ' one-way '
        self.driver.find_element_by_xpath('//*[@id="J-chepiao"]/div/div[1]/ul/li[1]/a').click()
        #  Eliminate the second pop-up 
        self.driver.find_element_by_link_text(' confirm ').click()

    def _search_ticket(self):
        # Place of departure input 
        self.driver.find_element_by_id("fromStationText").click()
        self.driver.find_element_by_id("fromStationText").send_keys(self.from_station)
        self.driver.find_element_by_id("fromStationText").send_keys(Keys.ENTER)
        # Destination input 
        self.driver.find_element_by_id("toStationText").click()
        self.driver.find_element_by_id("toStationText").send_keys(self.to_station)
        self.driver.find_element_by_id("toStationText").send_keys(Keys.ENTER)
        # Enter the departure date 
        self.driver.find_element_by_id("date_icon_1").click()

        # Wait to see if the button is available 
        WebDriverWait(self.driver,1000).until(EC.element_to_be_clickable((By.ID,"query_ticket")))
        # Execute click event 
        search_btn = self.driver.find_element_by_id("query_ticket")
        search_btn.click()
        # Wait for the ticket checking information to load 
        WebDriverWait(self.driver, 1000).until(EC.presence_of_element_located((By.XPATH, '//*[@id="queryLeftTable"]/tr')))

    def _order_ticket(self):
        train_num_list = []
        train_num_ele_list = self.driver.find_elements_by_xpath('//tr/td[1]/div/div[1]/div/a')
        for t in train_num_ele_list:
            train_num_list.append(t.text)
        tr_list = self.driver.find_elements_by_xpath('//*[@id="queryLeftTable"]/tr[not(@datatran)]')
        if self.train_num in train_num_list:
            for tr in tr_list:
                train_num = tr.find_element_by_xpath("./td[1]/div/div[1]/div/a").text
                if self.train_num == train_num:
                    # Information about second-class seats of bullet trains 
                    text_1 = tr.find_element_by_xpath("./td[4]").text
                    #  Second class ticket information 
                    text_2 = tr.find_element_by_xpath("./td[8]").text
                    if (text_1 == " Yes " or text_1.isdigit()) or (text_2 == " Yes " or text_2.isdigit()):
                        # Click the book button 
                        order_btn = tr.find_element_by_class_name("btn72")
                        order_btn.click()
                        # Waiting for the booking page 
                        WebDriverWait(self.driver,1000).until(EC.url_to_be(self.order_url))
                        #  Select passengers 
                        self.driver.find_element_by_xpath(f'//*[@id="normal_passenger_id"]/li/label[contains(text(),"{self.passenger}")]').click()
                        print(" Select passengers ")
                        # If the passenger is a student , Click OK... For the prompt 
                        if EC.presence_of_element_located((By.XPATH, '//div[@id="dialog_xsertcj"]')):
                            print(" Order submission ")

                            #  place order 
                            # self.driver.find_element_by_id('submitOrder_id').click()
                            time.sleep(2)
                            #  Click to confirm the order 
                            # self.driver.find_element_by_id('qr_submit_id').click()
                            self.Login_ti.tixing(self)
                        else:
                            #  place order 
                            print("else Order submission ")
                            self.driver.find_element_by_id('submitOrder_id').click()
                            self.Login_ti.tixing(self)
                            time.sleep(2)
                            #  Click on the confirmation 
                            # self.driver.find_element_by_id('qr_submit_id').click()


                            print(" Successful ticket purchase !")
                            break
                    else:
                        print(" There are no tickets for second-class seats !")
        else:
            print(" No such train !")

    def run(self):
        # Sign in 
        self._login()
        # Eliminate post login ( for the first time ) Pop-up windows 
        self._pop_window()
        # Enter the ticket purchase page 
        self._enter_order_ticket()
        # Ticket check 
        self._search_ticket()
        # booking 
        self._order_ticket()
        # Close the browser 
        time.sleep(6)
        self.driver.quit()

if __name__ == '__main__':
    qiangpiao = Qiangpiao(" Chengdu "," Chongqing ","2021-12-15","G8502"," Zhao Qin ","19102870304","tlmm123")
    qiangpiao.run()

The following code is to avoid my browser

option = ChromeOptions()
        option.add_experimental_option('excludeSwitches', ['enable-automation'])
        self.driver = webdriver.Chrome(options=option)

After being identified as testing the software , There will be such words , It cannot be verified at this time , But with the above code snippet, it won't be recognized



summary

Through the writing and debugging of multiple modules , The program can finally run successfully and buy tickets , But there are many more bug, It is constantly being revised , Some simple updates will be made later

copyright notice
author[justtodowell],Please bring the original link to reprint, thank you.
https://en.pythonmana.com/2022/02/202202021457358384.html

Random recommended