天天看點

Python實作全自動購買火車票!搶票回家過年咯

本文的文字及圖檔來源于網絡,僅供學習、交流使用,不具有任何商業用途,如有問題請及時聯系我們以作處理

PS:如有需要Python學習資料的小夥伴可以加點選下方連結自行擷取

python免費學習資料以及群交流解答點選即可加入

這個是實作結果,因為一天隻能取消三次,是以最後一步點選确認被我注釋了

Python實作全自動購買火車票!搶票回家過年咯

1.首先實作使用selenium登陸12306

 這裡實作了使用selenium登陸12306,實作全自動登陸12306連結

2.根據上面實作登陸後,實作購買火車票還需兩步

這裡隻進行了二等座的查詢和購票,想要買其他的自己也可以進行修改 1.進行車票的查詢 這裡面需要注意的是在輸入目的地和起始地時需要先click一下文本框browser.find_element_by_id(‘fromStationText’).click() 不然輸入的位址無效 還有将日期的隻讀屬性去掉

def search_railway_ticket(fromstation,tostation,train_date):

    # 火車票頁面查詢url

    search_url = 'https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc'

    # 轉到查詢車次頁面

    browser.get(search_url)

    time.sleep(2)

    #輸入出發地

    WebDriverWait(browser, 1000).until(

        EC.presence_of_element_located((By.ID, 'fromStationText'))

    )

    #先點選一下

    browser.find_element_by_id('fromStationText').click()

    browser.find_element_by_id('fromStationText').send_keys(fromstation)

    browser.find_element_by_id('fromStationText').send_keys(Keys.ENTER)

    time.sleep(1)

    WebDriverWait(browser, 1000).until(

        EC.presence_of_element_located((By.ID, 'toStationText'))

    )

    #輸入目的地

    browser.find_element_by_id('toStationText').click()

    browser.find_element_by_id('toStationText').send_keys(tostation)

    browser.find_element_by_id('toStationText').send_keys(Keys.ENTER)

    time.sleep(5)

    #将日期的隻讀屬性去掉

    js = 'document.getElementById("train_date").removeAttribute("readonly")'

    browser.execute_script(js)

    #去掉原本的時間

    WebDriverWait(browser, 1000).until(

        EC.presence_of_element_located((By.ID, 'train_date'))

    )

    browser.find_element_by_id("train_date").clear()

    #輸入出發時間

    browser.find_element_by_id('train_date').send_keys(train_date)

    # 等待查詢按鈕是否可用

    WebDriverWait(browser, 1000).until(

        EC.element_to_be_clickable((By.ID, 'query_ticket'))

    )

    searBtn = browser.find_element_by_id('query_ticket')

    searBtn.click()

    print('點選按鈕')

2.購買火車票 在這個函數中需要注意的是最好把最後一步注釋掉 browser.find_element_by_id(‘qr_submit_id’).click() 因為一天隻能取消3次訂單

def buy_ticket(fromstation,tostation,train_date,train_number,passenger):

    #查詢火車票

    search_railway_ticket(fromstation,tostation,train_date)

    time.sleep(5)

    #擷取每一個車次的資訊

    tr_list = browser.find_elements_by_xpath('.//tbody[@id="queryLeftTable"]/tr[not(@datatran)]')

    for tr in tr_list:

        #擷取車次号

        number = tr.find_element_by_class_name('number').text

        if number in  train_number:

            #擷取是否還有票

            left_ticket = tr.find_element_by_xpath('./td[4]').text

            if left_ticket =='有'or left_ticket.isdigit:

                print(f'{number}還有票')

                #點選預訂

                orderBtn = tr.find_element_by_class_name('btn72')

                orderBtn.click()

                time.sleep(5)

                #擷取12306中乘客的資訊

                passenger_list = browser.find_elements_by_xpath('//*[@id="normal_passenger_id"]/li')

                for li in passenger_list:

                    name = li.find_element_by_xpath('./label').text

                    print(name)

                    #配對12306人名

                    if name == passenger:

                        li.find_element_by_tag_name('input').click()

                #送出訂單

                submit = browser.find_element_by_id('submitOrder_id')

                submit.click()

                WebDriverWait(browser, 1000).until(

                    EC.element_to_be_clickable((By.ID, 'qr_submit_id'))

                )

                #一天隻能取消3次 是以最好把最後一步注釋了

                browser.find_element_by_id('qr_submit_id').click()

                print('已經送出訂單')

                break

下面是源代碼

測試的時候可以把#click_captcha()這個點選驗證碼的去掉自己手動點選,這樣就不用扣超級鷹的積分(有錢的話當我沒說),留下了貧窮的淚水。

from selenium import webdriver

from selenium.webdriver import Actionchains

import time

from PIL import Image

import requests

from hashlib import md5

from selenium.webdriver import ChromeOptions

#驗證碼識别處理

from selenium.webdriver.common.keys import Keys

from selenium.webdriver.common.by import By

from selenium.webdriver.support.wait import WebDriverWait

from selenium.webdriver.support import expected_conditions as EC

class Chaojiying_Client(object):

    def __init__(self, username, password, soft_id):

        self.username = username

        password =  password.encode('utf8')

        self.password = md5(password).hexdigest()

        self.soft_id = soft_id

        self.base_params = {

            'user': self.username,

            'pass2': self.password,

            'softid': self.soft_id,

        }

        self.headers = {

            'Connection': 'Keep-Alive',

            'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',

        }

    def PostPic(self, im, codetype):

        """

        im: 圖檔位元組

        codetype: 題目類型 參考 http://www.chaojiying.com/price.html

        """

        params = {

            'codetype': codetype,

        }

        params.update(self.base_params)

        files = {'userfile': ('ccc.jpg', im)}

        r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, headers=self.headers)

        return r.json()

    def ReportError(self, im_id):

        """

        im_id:報錯題目的圖檔ID

        """

        params = {

            'id': im_id,

        }

        params.update(self.base_params)

        r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)

        return r.json()

def login(username,password):

    # 填寫賬号密碼

    browser.find_element_by_id('J-userName').send_keys(username)

    browser.find_element_by_id('J-password').send_keys(password)

    # 擷取驗證碼

    get_captcha()

    # 填寫驗證碼

    click_captcha()

    #點選登入

    time.sleep(4)

    browser.find_element_by_id('J-login').click()

    time.sleep(4)

    #滑動驗證碼

    slider()

    print('成功登陸')

    time.sleep(5)

def slider():

    #滑動驗證碼

    WebDriverWait(browser, 1000).until(

        EC.presence_of_element_located((By.XPATH, '//*[@id="nc_1_n1z"]'))

    )

    span = browser.find_element_by_xpath('//*[@id="nc_1_n1z"]')

    # 對div_tag進行滑動操作

    action = Actionchains(browser)

    # 點選長按指定的标簽

    action.click_and_hold(span).perform()

    action.drag_and_drop_by_offset(span, 400, 0).perform()

def click_captcha():

    # 擷取驗證碼需要的為點選位置

    chaojiying = Chaojiying_Client('自己的使用者名', '密碼', '軟體id')  # 使用者中心>>軟體ID 生成一個替換 96001

    im = open('./captcha.png', 'rb').read()  # 本地圖檔檔案路徑 來替換 a.jpg 有時WIN系統須要//

    location = chaojiying.PostPic(im, 9004)['pic_str']  # 1902 驗證碼類型  官方網站>>價格體系 3.4+版 print 後要加()

    print(chaojiying.PostPic(im, 9004))

    # 将位置進行分割成    [  [  ], [ ], [ ]  ]類型

    location_list = [i.split(',') for i in location.split('|')]

    for l in location_list:

        x = l[0]

        y = l[1]

        Actionchains(browser).move_to_element_with_offset(browser.find_element_by_class_name('login-pwd-code'), int(x),int(y)).click().perform()

        time.sleep(0.5)

def get_captcha():

    # 擷取網頁的截圖

    allscreen = browser.get_screenshot_as_file('allscreen.png')

    # 擷取captcha

    captcha = browser.find_element_by_class_name('login-pwd-code')

    # 擷取captcha的左上角位置

    location = captcha.location

    # 擷取圖檔大小

    size = captcha.size

    # 裁取captcha

    rangle = (location['x'],location['y'],(location['x']+size['width']),(location['y']+size['height']))

    i = Image.open('./allscreen.png')

    captcha_img = './captcha.png'

    frame = i.crop(rangle)

    frame.save(captcha_img)

def buy_ticket(fromstation,tostation,train_date,train_number,passenger):

    #查詢火車票

    search_railway_ticket(fromstation,tostation,train_date)

    time.sleep(5)

    tr_list = browser.find_elements_by_xpath('.//tbody[@id="queryLeftTable"]/tr[not(@datatran)]')

    for tr in tr_list:

        number = tr.find_element_by_class_name('number').text

        if number in  train_number:

            left_ticket = tr.find_element_by_xpath('./td[4]').text

            if left_ticket =='有'or left_ticket.isdigit:

                print(f'{number}還有票')

                orderBtn = tr.find_element_by_class_name('btn72')

                orderBtn.click()

                time.sleep(5)

                passenger_list = browser.find_elements_by_xpath('//*[@id="normal_passenger_id"]/li')

                for li in passenger_list:

                    name = li.find_element_by_xpath('./label').text

                    if name == passenger:

                        li.find_element_by_tag_name('input').click()

                submit = browser.find_element_by_id('submitOrder_id')

                submit.click()

                WebDriverWait(browser, 1000).until(

                    EC.element_to_be_clickable((By.ID, 'qr_submit_id'))

                )

                #一天隻能取消3次 是以把最後一步注釋了

                # browser.find_element_by_id('qr_submit_id').click()

                print('已經送出訂單')

                break

def search_railway_ticket(fromstation,tostation,train_date):

    # 火車票頁面查詢url

    search_url = 'https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc'

    # 轉到查詢車次頁面

    browser.get(search_url)

    time.sleep(2)

    #輸入出發地

    WebDriverWait(browser, 1000).until(

        EC.presence_of_element_located((By.ID, 'fromStationText'))

    )

    #先點選一下

    browser.find_element_by_id('fromStationText').click()

    browser.find_element_by_id('fromStationText').send_keys(fromstation)

    browser.find_element_by_id('fromStationText').send_keys(Keys.ENTER)

    time.sleep(1)

    WebDriverWait(browser, 1000).until(

        EC.presence_of_element_located((By.ID, 'toStationText'))

    )

    #輸入目的地

    browser.find_element_by_id('toStationText').click()

    browser.find_element_by_id('toStationText').send_keys(tostation)

    browser.find_element_by_id('toStationText').send_keys(Keys.ENTER)

    time.sleep(5)

    #将日期的隻讀屬性去掉

    js = 'document.getElementById("train_date").removeAttribute("readonly")'

    browser.execute_script(js)

    #去掉原本的時間

    WebDriverWait(browser, 1000).until(

        EC.presence_of_element_located((By.ID, 'train_date'))

    )

    browser.find_element_by_id("train_date").clear()

    #輸入出發時間

    browser.find_element_by_id('train_date').send_keys(train_date)

    # 等待查詢按鈕是否可用

    WebDriverWait(browser, 1000).until(

        EC.element_to_be_clickable((By.ID, 'query_ticket'))

    )

    searBtn = browser.find_element_by_id('query_ticket')

    searBtn.click()

    print('點選按鈕')

if __name__ == '__main__':

    option = ChromeOptions()  # 執行個體化一個ChromeOptions對象

    option.add_experimental_option('excludeSwitches', ['enable-automation'])  # 以鍵值對的形式加入參數

    option.add_experimental_option('useAutomationExtension', False)

    browser = webdriver.Chrome(options=option)

    # 擷取響應

    browser.get('https://kyfw.12306.cn/otn/resources/login.html')

    script = 'Object.defineProperty(navigator,"webdriver",{get:()=>undefined,});'

    browser.execute_script(script)

    browser.maximize_window()

    time.sleep(1)

    # 點選賬号登陸

    browser.find_element_by_class_name('login-hd-account').click()

    #登陸12306的賬号密碼

    login('使用者名','密碼')

    time.sleep(4)

    #例buy_ticket('南昌','撫州北','2020-12-15','D2241','xx')

    buy_ticket('起始地','目的地','出發日期','車次','姓名')

想要擷取更多Python學習資料可以加

QQ:2955637827私聊

或加Q群630390733

大家一起來學習讨論吧!