您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > Python

Python实现全自动购买火车票!抢票回家过年咯

时间:2020-12-18 10:50:52  来源:  作者:

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

 

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

 

PS:如有需要Python/ target=_blank class=infotextkey>Python学习资料的小伙伴可以加点击下方链接自行获取



Tags:Python 火车票   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
这个是实现结果,因为一天只能取消三次,所以最后一步点击确认被我注释了 1.首先实现使用selenium登陆12306关于使用selenium实现12306登陆可以看我的另一篇文章 这里实现了使...【详细内容】
2020-12-18  Tags: Python 火车票  点击:(122)  评论:(0)  加入收藏
▌简易百科推荐
近几年 Web3 被炒得火热,但是大部分人可能还不清楚什么是 Web3,今天就让w3cschool编程狮小师妹带你了解下 Web3 是什么?与我们熟知的 Web1 和 Web2 又有什么区别呢?web3.0什么是...【详细内容】
2022-07-15  编程狮W3Cschool    Tags:Web3.0   点击:(2)  评论:(0)  加入收藏
1、让我们一起来看下吧,直接上图。 第一眼看到是不是觉得很高逼格,暗黑画风,这很大佬。其实它就是------AidLearning。一个运行在安卓平台的linux系统,而且还包含了许多非常强大...【详细内容】
2022-07-15  IT智能化专栏    Tags:AidLearning   点击:(2)  评论:(0)  加入收藏
真正的大师,永远都怀着一颗学徒的心! 一、项目简介 今天说的这个软件是一款基于Python+vue的自动化运维、完全开源的云管理平台。二、实现功能 基于RBAC权限系统 录像回放 ...【详细内容】
2022-07-14  菜鸟程序猿    Tags:Python   点击:(3)  评论:(0)  加入收藏
前言今天笔者想和大家来聊聊python接口自动化的MySQL数据连接,废话不多说咱们直接进入主题吧。 一、什么是 PyMySQL?PyMySQL是在Python3.x版本中用于连接MySQL服务器的一个库,P...【详细内容】
2022-07-11  测试架构师百里    Tags:python   点击:(19)  评论:(0)  加入收藏
aiohttp什么是 aiohttp?一个异步的 HTTP 客户端\服务端框架,基于 asyncio 的异步模块。可用于实现异步爬虫,更快于 requests 的同步爬虫。安装pip install aiohttpaiohttp 和 r...【详细内容】
2022-07-11  VT漫步    Tags:aiohttp   点击:(15)  评论:(0)  加入收藏
今天我们学习下 Queue 的进阶用法。生产者消费者模型在并发编程中,比如爬虫,有的线程负责爬取数据,有的线程负责对爬取到的数据做处理(清洗、分类和入库)。假如他们是直接交互的,...【详细内容】
2022-07-06  VT漫步    Tags:Python Queue   点击:(34)  评论:(0)  加入收藏
继承:是面向对象编程最重要的特性之一,例如,我们每个人都从祖辈和父母那里继承了一些体貌特征,但每个人却又不同于父母,有自己独有的一些特性。在面向对象中被继承的类是父类或基...【详细内容】
2022-07-06  至尊小狸子    Tags:python   点击:(25)  评论:(0)  加入收藏
点击上方头像关注我,每周上午 09:00准时推送,每月不定期赠送技术书籍。本文1553字,阅读约需4分钟 Hi,大家好,我是CoCo。在上一篇Python自动化测试系列文章:Python自动化测试之P...【详细内容】
2022-07-05  CoCo的软件测试小栈    Tags:Python   点击:(27)  评论:(0)  加入收藏
第一种方式:res = requests.get(url, params=data, headers = headers)第二种方式:res = requests.get(url, data=data, headers = headers)注意:1.url格式入参只支持第一种方...【详细内容】
2022-07-05  独钓寒江雪之IT    Tags:Python request   点击:(19)  评论:(0)  加入收藏
什么是python类的多态python的多态,可以为不同的类实例,或者说不同的数据处理方式,提供统一的接口。用比喻的方式理解python类的多态比如,同一个苹果(统一的接口)在孩子的眼里(类实...【详细内容】
2022-07-04  写小说的程序员    Tags:python类   点击:(28)  评论:(0)  加入收藏
站内最新
站内热门
站内头条