当前位置:   article > 正文

java + Selenium实现12306自动购票_java自动化脚本12306抢票怎么实现支付

java自动化脚本12306抢票怎么实现支付

为什么搞这个东西?【java + Selenium实现12306自动购票, 余票监测】
1.主要是12306是爬虫界的一个分水岭,所以我一直想玩12306【本次的实现并非真正意义上的破解12306实现购票,望周知】
2.一直看到微信群,朋友圈,甚至私发的携程 / 同程 购票加油包?点一下增加一个速度的那种~,想自实现一个
3.加深了解一下Selenium库的使用。【Selenium是一个自动化测试的工具库,主要用于测试,但是见仁见智,其实测试的很多东西都可以用于爬虫上面来。】
4.一直没上过12306购票,想了解一下整体购票流程,【其实是没坐过高铁~】

首先看看订单生成的效果

在这里插入图片描述

了解一下12306整体购票流程

在这里插入图片描述

了解一下本次程序的大概流程

  • 【___程序】打开浏览器进入12306官网
  • 【用户___】用户进行登录
  • 【___程序】进入搜索车次页面
  • 【用户___】等待用户输入 出发地 目的地 出发日 等信息
  • 【___程序】进行刷票,预订,提交订单
  • 【___程序】订单生成,打开网易云播放音乐
  • 【用户___】用户支付订单
  • 【___程序】购票结束,关闭浏览器

运行程序

  • 下拉最新代码 https://github.com/HouYuSource/spider
    具体实现源在:https://github.com/HouYuSource/spider/blob/master/src/main/java/cn/shaines/spider/module/china12306/TicketWorker2.java

    package cn.shaines.spider.module.china12306;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Scanner;
    import java.util.concurrent.ThreadLocalRandom;
    import org.apache.commons.lang3.StringUtils;
    import org.openqa.selenium.By;
    import org.openqa.selenium.JavascriptExecutor;
    import org.openqa.selenium.Keys;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.WebElement;
    import org.openqa.selenium.chrome.ChromeDriver;
    import org.openqa.selenium.interactions.Actions;
    import org.openqa.selenium.support.ui.ExpectedConditions;
    import org.openqa.selenium.support.ui.WebDriverWait;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     * @author houyu
     * @createTime 2019/9/2 11:17
     */
    public class TicketWorker2 {
    
        private static final Logger logger = LoggerFactory.getLogger(TicketWorker2.class);
        private static final String loginUrl = "https://kyfw.12306.cn/otn/resources/login.html";
        private static final String indexUrl = "https://kyfw.12306.cn/otn/view/index.html";
        private static final String searchUrl = "https://kyfw.12306.cn/otn/leftTicket/init";
        private static final String confirmUrl = "https://kyfw.12306.cn/otn/confirmPassenger/initDc";
    
    
        public static void main(String[] args) throws InterruptedException {
    
            // 打印初始化信息
            init();
            // 获取驱动
            WebDriver driver = getWebDriver();
            // 最大化
            driver.manage().window().maximize();
            // 处理登录
            handleLogin(driver);
            // 前往搜索
            handleSearch(driver);
            // 用户输入的车次
            String carCode = handleInputCarCode();
            // 处理预定
            handleReserve(driver, carCode);
            // 处理提交
            handleSubmit(driver);
            // 处理确认提交信息
            handleConfirm(driver);
            // 处理提醒用户
            handleCallUser(driver);
            // 睡眠等待用户确认信息完毕
            Thread.sleep(1000000);
            // 关闭浏览器
            driver.close();
    
    
        }
    
        private static void handleCallUser(WebDriver driver) throws InterruptedException {
    
            String windowHandle = driver.getWindowHandle();
            JavascriptExecutor executor = (JavascriptExecutor) driver;
            executor.executeScript("window.open('https://music.163.com/#/song?id=224877')");
            // 切换到网易云窗口
            Thread.sleep(1000);
            List<String> windowHandles = new ArrayList<>(driver.getWindowHandles());
            driver.switchTo().window(windowHandles.get(windowHandles.size() - 1));
            Thread.sleep(1000);
            driver.switchTo().frame("contentFrame");
            Thread.sleep(1000);
            driver.findElement(By.cssSelector("[id=content-operation]>a:first-child")).click();
            Thread.sleep(1000);
            driver.switchTo().window(windowHandle);
        }
    
        private static void handleConfirm(WebDriver driver) throws InterruptedException {
            Thread.sleep(1000);
            if(driver.findElements(By.cssSelector("#checkticketinfo_id #qr_submit_id")).size() > 0) {
                // 点击确认订单信息
                driver.findElements(By.cssSelector("#checkticketinfo_id #qr_submit_id")).get(0).click();
            }
            logger.debug("购票成功");
        }
    
        private static void handleSubmit(WebDriver driver) throws InterruptedException {
            Thread.sleep(1000);
            driver.findElement(By.cssSelector("#normalPassenger_0")).click();
            //
            do {
                if(driver.findElements(By.cssSelector("#transforNotice_id #qr_closeTranforDialog_id")).size() > 0) {
                    // 这里有可能会出现网络繁忙的情况, 如果出现就点击确认, 关闭窗口, 然后再重试
                    driver.findElement(By.cssSelector("#transforNotice_id #qr_closeTranforDialog_id")).click();
                }
                Thread.sleep(1000);
                driver.findElement(By.cssSelector("#submitOrder_id")).click();
                //
            } while(driver.findElements(By.cssSelector("#transforNotice_id #qr_closeTranforDialog_id")).size() > 0);
        }
    
        private static void handleLogin(WebDriver driver) {
            driver.get(loginUrl);
            logger.debug("等待用户登录");
            // 登录成功
            WebDriverWait wait = new WebDriverWait(driver, 120);
            wait.until(ExpectedConditions.urlContains(indexUrl));
            logger.debug("用户登录成功~");
        }
    
        private static void handleReserve(WebDriver driver, String carCode) throws InterruptedException {
            clickSearch : for (int i = 1; ; i++) {
                List<WebElement> trs = driver.findElements(By.cssSelector("table tbody#queryLeftTable:first-of-type tr"));
                for (WebElement tr : trs) {
                    if (tr.getAttribute("id").contains("ticket_")) {
                        String currentCarCode = tr.findElements(By.cssSelector("td div.ticket-info > div.train a.number")).get(0).getText();
                        if (carCode.equals(currentCarCode)) {
                            // 找到了车次
                            WebElement purchaseTd = tr.findElement(By.cssSelector("td:last-of-type"));
                            String text = purchaseTd.getText();
                            logger.debug("找到预定text:" + text);
                            List<WebElement> aElementList = purchaseTd.findElements(By.tagName("a"));
                            if (aElementList.size() > 0) {
                                logger.debug("点击预定:");
                                purchaseTd.click();
                                Thread.sleep(1000);
                                if (driver.findElements(By.id("defaultwarningAlert_id")).size() > 0) {
                                    // 可能出现不可以预定时间
                                    List<WebElement> tips = driver.findElements(By.id("content_defaultwarningAlert_hearder"));
                                    if (tips.size() > 0) {
                                        String tip = tips.get(0).getText();
                                        logger.debug("预定失败:" + tip);
                                    }
                                    // 关闭弹窗
                                    driver.findElement(By.id("qd_closeDefaultWarningWindowDialog_id")).click();
                                    continue clickSearch;
                                }
                                // 需要处理登录问题
                                break clickSearch;
                            }
                        }
                    }
                }
                // 没有找到车次, 或者, 点击查询按钮, 10次刷新一下页面
                if (i % 10 == 0) {
                    logger.debug("重新刷新页面");
                    driver.navigate().refresh();
                    continue;
                }
                long sleepTime = ThreadLocalRandom.current().nextLong(800, 2000);
                Thread.sleep(sleepTime);
                List<WebElement> query_ticket = driver.findElements(By.id("query_ticket"));
                if (query_ticket.size() > 0) {
                    logger.debug("准备点击查询更新数据第: " + i + " 次");
                    query_ticket.get(0).click();
                    // 等待页面数据出来
                    WebDriverWait wait = new WebDriverWait(driver, 120);
                    wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("table tbody#queryLeftTable:first-of-type tr")));
                } else {
                    logger.debug("查询按钮不可用");
                }
            }
        }
    
        private static String handleInputCarCode() {
            System.err.println("=============================请在下方输入你需要抢购的车次==================================");
            String carCode = null;
            try (Scanner scanner = new Scanner(System.in)) {
                while (StringUtils.isEmpty(carCode)) {
                    System.out.println();
                    carCode = scanner.nextLine();
                }
            }
            System.out.println("您输入的车次为:" + carCode);
            return carCode;
        }
    
        private static void handleSearch(WebDriver driver) {
            driver.get(searchUrl);
            System.out.println();
            System.err.println("请在打开的浏览器页面中填写 '出发地' '目的地' '出发日' 等相关信息, 并且点击 '查询' 按钮完成本次操作");
            // 获取搜索的条数
            WebDriverWait wait = new WebDriverWait(driver,120);
            wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("table tbody#queryLeftTable:first-of-type tr")));
            List<WebElement> trs = driver.findElements(By.cssSelector("table tbody#queryLeftTable:first-of-type tr"));
            List<String> currentCarCodeList = new ArrayList<>(16);
            for (WebElement tr : trs) {
                if (tr.getAttribute("id").contains("ticket_")) {
                    String currentCarCode = tr.findElements(By.cssSelector("td div.ticket-info > div.train a.number")).get(0).getText();
                    currentCarCodeList.add(currentCarCode);
                }
            }
            System.out.println("本次查找到车次数量为: " + currentCarCodeList.size());
            for (int i = 0; i < currentCarCodeList.size(); i++) {
                String currentCarCode = currentCarCodeList.get(i);
                System.out.print(currentCarCode + "\t||\t");
                if (i % 5 == 1) {
                    System.out.println();
                }
            }
        }
    
        private static void init() {
            System.out.println();
            System.out.println("‖======================= 欢迎使用 12306 抢票助手 ========================‖");
            System.out.println("‖                                                                      ‖");
            System.out.println("‖                                   使用过程中如果有任何问题欢迎反馈       ‖");
            System.out.println("‖                                   mail : for.houyu@foxmail.com       ‖");
            System.out.println("‖                                   version : V1.0                     ‖");
            System.out.println("‖                                   powered by houyu                   ‖");
            System.out.println("‖                                                                      ‖");
            System.out.println("‖======================= 欢迎使用 12306 抢票助手 ========================‖");
            System.out.println();
            System.out.println();
            System.out.println();
        }
    
        private static WebDriver getWebDriver() {
            // System.setProperty("webdriver.chrome.driver", "C:\\install\\chromedriver\\chromedriver.exe");// chromedriver地址
            System.setProperty("webdriver.chrome.driver", "src/main/resources/chromedriver.exe");// chromedriver地址
            WebDriver driver = new ChromeDriver(); // 新建一个WebDriver 的对象,但是new 的是谷歌的驱动
            return driver;
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
  • 安装google浏览器(谷歌内核的浏览器, 版本76.0.3809.132+)

  • 结合程序控制台输出,进行浏览器操作等

    ======================= 欢迎使用 12306 抢票助手 ========================‖
    ‖                                                                      ‖
    ‖                                   使用过程中如果有任何问题欢迎反馈       ‖
    ‖                                   mail : for.houyu@foxmail.com       ‖
    ‖                                   version : V1.0                     ‖
    ‖                                   powered by houyu                   ‖
    ‖                                                                      ‖
    ‖======================= 欢迎使用 12306 抢票助手 ========================‖
    
    
    
    Starting ChromeDriver 76.0.3809.126 (d80a294506b4c9d18015e755cee48f953ddc3f2f-refs/branch-heads/3809@{#1024}) on port 11230
    Only local connections are allowed.
    Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code.
    [1568739524.884][WARNING]: Timed out connecting to Chrome, retrying...
    九月 18, 2019 12:58:47 上午 org.openqa.selenium.remote.ProtocolHandshake createSession
    信息: Detected dialect: W3C
    [1568739529.158][WARNING]: Timed out connecting to Chrome, retrying...
    00:58:52.142 [main] DEBUG cn.shaines.spider.module.china12306.TicketWorker2 - 等待用户登录
    ...
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

Selenium的实现的购票程序优缺点

优点

  • 流程简单,快速实现
  • 页面可视化,有感知

弊端

  • 效率低,性能差【相对而言,其实在这购票上面,你也不敢刷得很快,因为都是实名制的,小心进入黑名单,虽然也有办法规避】
  • 网站购票指南改变,程序不可用
  • 未知问题无法掌握【有可能出现乱七八糟的弹窗都会导致整体的程序挂掉】

规划

  • 实现脱离java环境运行,也就是打包为一个.exe文件等形式
  • 进行模块化,组件化,方便日后维护以及打补丁等

理想发展

使用python实现代码级别的破解【可以了解github: 12306 / py12306】

  • 自动打码【网上有开源针对12306的验证码深度学习库,据说准确率高达98%】
  • 自动登录
  • 无限刷票
  • 自动下单
  • 自动支付
  • 订单通知

整体流程都看了一遍,发现12306也有几个难点,
其中最难的应该是登录验证码,人看点击都输入错误好几次【这个可接入开源12306打码进行破解】,
其次是请求车次数据的解析,返回的数据有点乱,但是还是有很多可阅读数据的,还没深入DEBUG看,但是感觉不是很难的那种混淆,
除此之外尚未发现比价复杂的点,等闲下来有时间可以玩玩~~

最后的话

  • 本程序最后验证时间是:2019-09-17
  • 本程序切勿使用商业用途
  • 程序尚未使用IP池,切勿多实例(启动多次)购票
  • 不会帮助购买票的~但是你在使用过程中遇到什么问题欢迎一起讨论
  • 没有义务帮忙解决一切问题

如果你也是一名爬虫爱好者,或者有了解过12306的相关爬虫,欢迎我们一起讨论
blog: https://shaines.cn
mail : for.houyu@foxmail.com
csdn: https://blog.csdn.net/jinglongsou

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/632119
推荐阅读
相关标签
  

闽ICP备14008679号