这个是实现结果,因为一天只能取消三次,所以最后一步点击确认被我注释了

python火车票订票模拟 python火车票购买程序_python火车票订票模拟

1.首先实现使用selenium登陆12306

关于使用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('起始地','目的地','出发日期','车次','姓名')