本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理

这个是实现结果,因为一天只能取消三次,所以最后一步点击确认被我注释了
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
大家一起来学习讨论吧!

Python实现全自动购买火车票!抢票回家过年咯的更多相关文章

  1. 春运到了,带你用python来抢票回家!

    不知不觉,一年一度的春运抢票大幕已经拉开,想快速抢到回家的车票吗?作为程序员,这些技术手段,你一定要知道. 为了让大家更快捷更便利的抢火车票,各种各样的抢票软件应需而生,这类软件大部分都是付费抢票的机 ...

  2. 火车票抢票API 根据乘客的车次与座席要求快速订票出票

    火车票抢票API 根据乘客的车次与座席要求快速订票出票:https://www.juhe.cn/docs/api/id/257 1.站站查询 接口地址:http://v.juhe.cn/grabTic ...

  3. python 并发编程 多进程 模拟抢票

    抢票是并发执行 多个进程可以访问同一个文件 多个进程共享同一文件,我们可以把文件当数据库,用多个进程模拟多个人执行抢票任务 db.txt {"count": 1} 并发运行,效率高 ...

  4. 实测两款 GitHub 开源抢票插件,所有坑都帮你踩过了

    如果你对自己手速和市面上的各种 “加速包” 都没什么信心的话,不妨试试用程序员的手段抢票? 况且,[12306 官方宣布屏蔽了一大批付费抢票软件],这也意味着你即使给这些软件付了会员费,也依旧抢不到票 ...

  5. 四、基于HTTPS协议的12306抢票软件设计与实现--水平DNS并发查询分享

    一.基于HTTPS协议的12306抢票软件设计与实现--实现效果 二.基于HTTPS协议的12306抢票软件设计与实现--相关接口以及数据格式 三.基于HTTPS协议的12306抢票软件设计与实现-- ...

  6. 智行火车票免费加速到VIP最高速抢票(不用朋友积攒或者购买加速包)

    更新: 2018.11.07, 昨天我买火车票,已经不行了,这个bug已经没有了,被修复了, 望大家知悉!!! 智行火车票免费加速到VIP最高速抢票(不用朋友积攒或者购买加速包) 1)下过单后选择抢到 ...

  7. 用Python抢到回家的车票,so easy!

    “ 盼望着,盼望着,春节的脚步近了,然而,每年到这个时候,最难的,莫过于一张回家的火车票. ​ 据悉,今年春运期间,全国铁路发送旅客人次同比将增长 8.0%.达到 4.4 亿人次. ​ 2020 年铁 ...

  8. 简单的Python 火车抢票程序

    当你想查询一下火车票信息的时候,你还在上12306官网吗?或是打开你手机里的APP?下面让我们来用Python写一个命令行版的火车票查看器, 只要在命令行敲一行命令就能获得你想要的火车票信息!如果你刚 ...

  9. Python操作12306抢票脚本

    有一段时间没有使用Python了,前几天经朋友提起一篇关于用Python实现抢火车票的文章,百度了实现抢火车票的技术细节,网上却有不少资料,也不是新鲜的东西.在了解了一些技术手段,阅读了一些大神的博文 ...

随机推荐

  1. Logstash使用mongodb插件报错: ArgumentError: wrong number of arguments (given 2, expected 1)

    目录 背景 安装插件过程 背景 今天在使用logstash收集日志存储到mongodb的安装过程遇到了个错误,记录下来,错误就是下面这样: 配置文件很简单,由于是测试环境,命令行传入日志输入由ruby ...

  2. 堆的数据结构java

    public class MaxHeap { private int[] data; private int count; private int capacity; public MaxHeap(i ...

  3. jenkins、gitlab配置CI/CD

    1. 在gitlab中创建好项目(gitlab的安装和基本使用这里不在说明) 2. 创建jenkins任务 jenkins 需要几个插件请先安装好 - Git plugin - GitLab Plug ...

  4. 写给程序员的机器学习入门 (九) - 对象识别 RCNN 与 Fast-RCNN

    因为这几个月饭店生意恢复,加上研究 Faster-RCNN 用掉了很多时间,就没有更新博客了.这篇开始会介绍对象识别的模型与实现方法,首先会介绍最简单的 RCNN 与 Fast-RCNN 模型,下一篇 ...

  5. 【原创】视频+文字:详解VBA解决数独问题

    [说在前面]: 之前,我在微信朋友圈看到一个同事发了一个状态,说的是她在家辅导孩子做作业,一个数独的题目,好像没有做出来.我看了下,我也做不出来,后来仔细想了下,花了两个多小时时间,用Python编了 ...

  6. C++stl简单使用

    1 //1.sort函数排序 2 /* 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; ...

  7. 不使用 MQ 如何实现 pub/sub 场景?

    hello,大家好,我是小黑,又和大家见面啦~~ 在配置中心中,有一个经典的 pub/sub 场景:某个配置项发生变更之后,需要实时的同步到各个服务端节点,同时推送给客户端集群. 在之前实现的简易版配 ...

  8. MySQL下载及使用

    MySQL下载及使用 在下载MySQL的过程当中一般都不会下载最新版本的软件,因为最新版本的MySQL可能会出现各种问题,也不推荐在原来的版本上更新到最新版本,因为这样可能导致原本项目能正常运行,更新 ...

  9. Java数据结构(十三)—— 二叉排序树(BST)

    二叉排序树(BST) 需求 给定数列{7,3,10,12,5,1,9},要求能够高效的完成对数据的查询和添加 思路三则 使用数组,缺点:插入和排序速度较慢 链式存储,添加较快,但查找速度慢 使用二叉排 ...

  10. day102:MoFang:后端完成对短信验证码的校验&基于celery完成异步短信发送&flask_jwt_extended&用户登录的API接口

    目录 1.用户注册 1.后端完成对短信验证码的校验 2.基于celery实现短信异步发送 2.用户登录 1.jwt登录验证:flask_jwt_extended 2.服务端提供用户登录的API接口 1 ...