为什么搞这个东西?【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;}}
  • 安装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 - 等待用户登录
    ...
    ...
    

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

java + Selenium实现12306自动购票相关推荐

  1. 28. 实战:基于selenium实现12306自动购票

    目录 前言 目的 思路 代码实现 1. 进入登录界面,输入账号密码 2. 点击登录按钮,完成滑块验证 3. 在个人中心点击购票,跳转 4. 输入出发地.目的地,从控制台输入得到 5. 文本框输入出发日 ...

  2. 爬虫日常-12306自动购票程序

    文章目录 前言 页面分析 代码设计 前言 hello兄弟们,最近在钻研新鲜知识,一不留神没想起来更新.今天我们顺着前面几篇文章完整的写出一篇12306的自动购票软件. 首先把我们已经写完的前期步骤代码 ...

  3. selenium实现12306火车购票网站滑块自动验证登录

    解决滑块验证登录问题和网站禁止selenium操作无法通过验证问题,问题过程如下,亲测有效: 当输入账号密码,点击登录后出现如下滑动解锁框: 此时,完成滑块自动滑动至右边解锁,写个拖动滑块的函数 mo ...

  4. python+selenium实现12306自动登录刷票抢票(自己做黄牛?!)

    上一篇写了12306的自动登录破解验证图https://blog.csdn.net/weixin_38283159/article/details/86498159 这篇算是它的后续部分加上了简单的刷 ...

  5. 爬虫练习-12306自动购票升级版

    文章目录 前言 代码更新 前言 hello兄弟们,偷懒归来了.别问为啥这么久没更,问就是失踪了 最近一直在学习Django以及爬虫进阶之类的知识,加上快期末了,一直没有想起来自己还有一个账号没有更新, ...

  6. 12306自动购票 ,抓包分析

    我是在文本编辑工具里写的,然后复制到CSDN格式有点乱,你们可以粘贴到文本编辑工具中慢慢分析 9 首页:   https://kyfw.12306.cn/otn/login/init 12 没有参数 ...

  7. 计算机编程购票代码,12306自动购票脚本

    ticket.py # -*- coding: utf-8 -*- """ @author: aiyou """ from splinter ...

  8. 快过年了,Python实现12306查票以及自动购票....

    嗨害大家好鸭!我是小熊猫~ 明天就是2023年啦~ 还有谁像我小熊猫一样没有回家的? 这次康康能不能12306抢票回家!!! Python实现12306查票以及自动购票 [代码来源]: 青灯教育-自游 ...

  9. python+splinter实现12306网站刷票并自动购票流程

    python+splinter实现12306网站刷票并自动购票流程 通过python+splinter,实现在12306网站刷票并自动购票流程(无法自动识别验证码). 此类程序只是提高了12306网站 ...

最新文章

  1. 应用层网关调研与基础测试
  2. MySQL手机统计信息_MySQL统计信息
  3. geohash vs PostGIS
  4. P2408 不同子串个数
  5. java多线程之ThreadLoal详解
  6. DeepMind科学家:强化学习足以满足通用AI需求
  7. 你还在做描述性数据分析吗?卡方检验案例实操
  8. IBM ThinkPad错误代码列表
  9. Numpy系列(七)求解线性方程组、计算逆矩阵求解线性方程组
  10. 63. (FileInputStream)输入字节流
  11. (转)思科VPP源码分析(feature机制分析)
  12. Linux中 查看mysql配置文件位置
  13. Julia 下载 安装 juno 开发环境搭建
  14. 基于Verilog HDL的数字时钟
  15. xmanager 修改linux ip,Linux配置XManager
  16. 复工后,企业裁员、降薪前必须了解的10个法律问题
  17. 润和软件助力深圳集成电路应用开发职业技能竞赛圆满收官
  18. 短信阅读率接近100%?短信营销用“短链接”提升推广效果
  19. 易语言和python融合_易语言和python融合|智联招聘怎么自动投递简历
  20. php 连接mysql连接被重置的解决方法

热门文章

  1. You Can’t Future-Proof Solutions
  2. Unity小游戏-平衡大师(安卓、PC、web)2D益智类游戏 项目展示+完整项目源码
  3. 简单的UI框架 | 一、UI界面的搭建
  4. 简单内存泄漏检测方法,解决Detected memory leaks!问题 .
  5. Python人脸识别项目-人脸识别-获取人脸图片
  6. gif太大了怎么压缩?教你一招轻松压缩gif大小
  7. MacBook Pro 2018电池鼓包、键盘问题免费换新
  8. 华硕顽石第四代FL5900u拆机换电池
  9. BUUCTF 打卡2
  10. 集成智能小车(二...2)整体设计之谋