java + Selenium实现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.javapackage 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自动购票相关推荐
- 28. 实战:基于selenium实现12306自动购票
目录 前言 目的 思路 代码实现 1. 进入登录界面,输入账号密码 2. 点击登录按钮,完成滑块验证 3. 在个人中心点击购票,跳转 4. 输入出发地.目的地,从控制台输入得到 5. 文本框输入出发日 ...
- 爬虫日常-12306自动购票程序
文章目录 前言 页面分析 代码设计 前言 hello兄弟们,最近在钻研新鲜知识,一不留神没想起来更新.今天我们顺着前面几篇文章完整的写出一篇12306的自动购票软件. 首先把我们已经写完的前期步骤代码 ...
- selenium实现12306火车购票网站滑块自动验证登录
解决滑块验证登录问题和网站禁止selenium操作无法通过验证问题,问题过程如下,亲测有效: 当输入账号密码,点击登录后出现如下滑动解锁框: 此时,完成滑块自动滑动至右边解锁,写个拖动滑块的函数 mo ...
- python+selenium实现12306自动登录刷票抢票(自己做黄牛?!)
上一篇写了12306的自动登录破解验证图https://blog.csdn.net/weixin_38283159/article/details/86498159 这篇算是它的后续部分加上了简单的刷 ...
- 爬虫练习-12306自动购票升级版
文章目录 前言 代码更新 前言 hello兄弟们,偷懒归来了.别问为啥这么久没更,问就是失踪了 最近一直在学习Django以及爬虫进阶之类的知识,加上快期末了,一直没有想起来自己还有一个账号没有更新, ...
- 12306自动购票 ,抓包分析
我是在文本编辑工具里写的,然后复制到CSDN格式有点乱,你们可以粘贴到文本编辑工具中慢慢分析 9 首页: https://kyfw.12306.cn/otn/login/init 12 没有参数 ...
- 计算机编程购票代码,12306自动购票脚本
ticket.py # -*- coding: utf-8 -*- """ @author: aiyou """ from splinter ...
- 快过年了,Python实现12306查票以及自动购票....
嗨害大家好鸭!我是小熊猫~ 明天就是2023年啦~ 还有谁像我小熊猫一样没有回家的? 这次康康能不能12306抢票回家!!! Python实现12306查票以及自动购票 [代码来源]: 青灯教育-自游 ...
- python+splinter实现12306网站刷票并自动购票流程
python+splinter实现12306网站刷票并自动购票流程 通过python+splinter,实现在12306网站刷票并自动购票流程(无法自动识别验证码). 此类程序只是提高了12306网站 ...
最新文章
- 应用层网关调研与基础测试
- MySQL手机统计信息_MySQL统计信息
- geohash vs PostGIS
- P2408 不同子串个数
- java多线程之ThreadLoal详解
- DeepMind科学家:强化学习足以满足通用AI需求
- 你还在做描述性数据分析吗?卡方检验案例实操
- IBM ThinkPad错误代码列表
- Numpy系列(七)求解线性方程组、计算逆矩阵求解线性方程组
- 63. (FileInputStream)输入字节流
- (转)思科VPP源码分析(feature机制分析)
- Linux中 查看mysql配置文件位置
- Julia 下载 安装 juno 开发环境搭建
- 基于Verilog HDL的数字时钟
- xmanager 修改linux ip,Linux配置XManager
- 复工后,企业裁员、降薪前必须了解的10个法律问题
- 润和软件助力深圳集成电路应用开发职业技能竞赛圆满收官
- 短信阅读率接近100%?短信营销用“短链接”提升推广效果
- 易语言和python融合_易语言和python融合|智联招聘怎么自动投递简历
- php 连接mysql连接被重置的解决方法
热门文章
- You Can’t Future-Proof Solutions
- Unity小游戏-平衡大师(安卓、PC、web)2D益智类游戏 项目展示+完整项目源码
- 简单的UI框架 | 一、UI界面的搭建
- 简单内存泄漏检测方法,解决Detected memory leaks!问题 .
- Python人脸识别项目-人脸识别-获取人脸图片
- gif太大了怎么压缩?教你一招轻松压缩gif大小
- MacBook Pro 2018电池鼓包、键盘问题免费换新
- 华硕顽石第四代FL5900u拆机换电池
- BUUCTF 打卡2
- 集成智能小车(二...2)整体设计之谋