python3.7之12306搶票腳本實現


  悲催的12306,徹底淪為各路搶票軟件的服務提供方。元旦伊始,純粹12306官網及APP搶票,愈一周的時間,僅到手一張凌晨3:55回家的站票。為遠離腦殘,無奈選擇搶票軟件,預購年后返滬車票。BTW,研究一下搶票腳本的實現思路,參考:(https://juejin.im/post/5b116504f265da6e0636cbc2 - Python3.6實現12306火車票自動搶票)。

  在原作者之上,對執行代碼做了以下處理:

  1. 刪除短信/郵件通知功能
  2. 刪除控制台輸入功能
  3. 新增登陸cookie的刷新
  4. 新增多車次搶票
  5. 新增多座位類型搶票

  注:使用 splinter.browser 在調用時,注意將 chrome驅動路徑(chromedriver.exe所在)配置在環境變量 -  path 下。

代碼如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from splinter.browser import Browser
from time import sleep
import sys

class BrushTicket(object):
    """買票類及實現方法"""
    def __init__(self, passengers, from_time, from_station, to_station, number_seat):
        """定義實例屬性,初始化"""
        # 乘客姓名
        self.passengers = passengers
        # 起始站和終點站
        self.from_station = from_station
        self.to_station = to_station
        # 乘車日期
        self.from_time = from_time
        # 車次 - 座位 dict
        num_seat_dic = {}
        for num_seat in number_seat:
            use = num_seat.split(':')
            num = use[0]
            seats = use[1]
            seats_use = seats.split(',')
            seat_str = ''
            for seat in seats_use:
                # 座位類型所在td位置
                if seat == '商務座特等座':
                    seat_type_index = 1
                    seat_type_value = 9
                elif seat == '一等座':
                    seat_type_index = 2
                    seat_type_value = 'M'
                elif seat == '二等座':
                    seat_type_index = 3
                    seat_type_value = 0
                elif seat == '高級軟卧':
                    seat_type_index = 4
                    seat_type_value = 6
                elif seat == '軟卧':
                    seat_type_index = 5
                    seat_type_value = 4
                elif seat == '動卧':
                    seat_type_index = 6
                    seat_type_value = 'F'
                elif seat == '硬卧':
                    seat_type_index = 7
                    seat_type_value = 3
                elif seat == '軟座':
                    seat_type_index = 8
                    seat_type_value = 2
                elif seat == '硬座':
                    seat_type_index = 9
                    seat_type_value = 1
                elif seat == '無座':
                    seat_type_index = 10
                    seat_type_value = 1
                elif seat == '其他':
                    seat_type_index = 11
                    seat_type_value = 1
                else:
                    seat_type_index = 7
                    seat_type_value = 3
                seat_str += (str(seat_type_index) + '-' + str(seat_type_value) + ',')
            num_seat_dic[num] = seat_str
        self.num_seat_dic = num_seat_dic
        # 新版12306官網主要頁面網址
        self.login_url = 'https://kyfw.12306.cn/otn/resources/login.html'
        self.init_my_url = 'https://kyfw.12306.cn/otn/view/index.html'
        self.ticket_url = 'https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc'
        # 瀏覽器驅動信息,驅動下載頁:https://sites.google.com/a/chromium.org/chromedriver/downloads
        self.driver_name = 'chrome'
        self.driver = Browser("chrome")
    def do_login(self):
        """登錄功能實現,手動識別驗證碼進行登錄"""
        self.driver.visit(self.login_url)
        sleep(1)
        # 選擇登陸方式登陸
        print('請掃碼登陸或者賬號登陸……')
        while True:
            if self.driver.url != self.init_my_url:
                sleep(1)
            else:
                break
    def start_brush(self):
        """買票功能實現"""
        # 瀏覽器窗口最大化
        self.driver.driver.maximize_window()
        # 登陸
        self.do_login()
        # 跳轉到搶票頁面
        self.driver.visit(self.ticket_url)
        try:
            print('開始刷票……')
            # 加載車票查詢信息
            self.driver.cookies.add({"_jc_save_fromStation": self.from_station})
            self.driver.cookies.add({"_jc_save_toStation": self.to_station})
            self.driver.cookies.add({"_jc_save_fromDate": self.from_time})
            self.driver.reload()
            count = 0
            while self.driver.url == self.ticket_url:
                self.driver.find_by_text('查詢').click()
                sleep(1)
                count += 1
                print('第%d次點擊查詢……' % count)
                if count % 50 == 0:
                    self.driver.find_by_id('login_user').click()
                    sleep(1)
                    self.driver.visit(self.ticket_url)
                    sleep(1)
                    print('繼續刷票......')
                    # 加載車票查詢信息
                    self.driver.cookies.add({"_jc_save_fromStation": self.from_station})
                    self.driver.cookies.add({"_jc_save_toStation": self.to_station})
                    self.driver.cookies.add({"_jc_save_fromDate": self.from_time})
                    self.driver.reload()
                    if self.driver.url == self.ticket_url:
                        continue
                try:
                    # 多車次處理
                    for bander in self.num_seat_dic.keys():
                        current_tr = self.driver.find_by_xpath('//tr[@datatran="' + bander + '"]/preceding-sibling::tr[1]')
                        if current_tr:
                            # 多座次處理
                            seat_value = self.num_seat_dic[bander]
                            seat_split = seat_value.split(',')
                            for seat in seat_split:
                                if seat:
                                    seat_type = seat.split('-')
                                    seat_type_index = int(seat_type[0])
                                    seat_type_value = int(seat_type[1])
                                    if current_tr.find_by_tag('td')[seat_type_index].text == '--':
                                        print(bander + ' 還未出售')
                                        sleep(1)
                                    elif current_tr.find_by_tag('td')[seat_type_index].text == '無':
                                        print(bander + ' 無票,繼續嘗試……')
                                        sleep(1)
                                    else:
                                        # 有票,嘗試預訂
                                        print(bander + ' 刷到票了(余票數:' + str(
                                            current_tr.find_by_tag('td')[seat_type_index].text) + '),開始嘗試預訂……')
                                        current_tr.find_by_css('td.no-br>a')[0].click()
                                        sleep(1)
                                        key_value = 1
                                        for p in self.passengers:
                                            # 選擇用戶
                                            print('開始選擇用戶……')
                                            self.driver.find_by_text(p).last.click()
                                            # 選擇座位類型
                                            print('開始選擇席別……')
                                            if seat_type_value != 0:
                                                self.driver.find_by_xpath(
                                                    "//select[@id='seatType_" + str(key_value) + "']/option[@value='" + str(
                                                        seat_type_value) + "']").first.click()
                                            key_value += 1
                                            sleep(0.2)
                                            if p[-1] == ')':
                                                self.driver.find_by_id('dialog_xsertcj_ok').click()
                                        print('正在提交訂單……')
                                        self.driver.find_by_id('submitOrder_id').click()
                                        sleep(2)
                                        # 查看放回結果是否正常
                                        submit_false_info = self.driver.find_by_id('orderResultInfo_id')[0].text
                                        if submit_false_info != '':
                                            print(submit_false_info)
                                            self.driver.find_by_id('qr_closeTranforDialog_id').click()
                                            sleep(0.2)
                                            self.driver.find_by_id('preStep_id').click()
                                            sleep(0.3)
                                            continue
                                        print('正在確認訂單……')
                                        self.driver.find_by_id('qr_submit_id').click()
                                        print('預訂成功,請及時前往支付……')
                        else:
                            print('不存在當前車次【%s】,已結束當前刷票,請重新開啟!' % self.number)
                            sys.exit(1)
                except Exception as error_info:
                    print(error_info)
        except Exception as error_info:
            print(error_info)
if __name__ == '__main__':
    # nya
    passengers=['***'] # 用戶名
    from_time='2019-02-01' # 出發日期
    from_station='%u4E0A%u6D77%2CSHH'  # 起始站點 - 來自12306 余票查詢 請求 - cookie (此處 - 上海)
    to_station='%u6C11%u6743%2CMQF' # 結束站點 (此處 - 民權)
    number_seat=['K4054:硬座,無座','K4168:硬座,無座'] # 車次:座位類型
    # 開始搶票
    ticket = BrushTicket(passengers, from_time, from_station, to_station, number_seat)
    ticket.start_brush()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM