前两天女友要在线订火车在票,一直都没有办法订到票,最后没办法,便给她写了个自动抢票的脚本,可周边的朋友听她说通过软件订到票了,都先后向她要软件,可原来的脚本只是基于控制台输入,这样给别人也没法用,兴趣一起,就花了一天的时间做了个WEB界面,然后分享给朋友用。先上几张图,看大家看看。
这个是登录界面,要使用前先设置一下常用的邮箱和登录密码,自动抢票过程中,如需要再输入登录验证码和订单验证码,或订单成功时,将通过此email通知您,建议使用qq邮箱,这样只要您在电脑时开打QQ,收到邮件时,qq会弹出窗口通知您,您可以即时响应。
第一次使用时,要先把在火车票官网注册的资料填在这里:
这资料都必码是已在官方上注册过的,在自动订票时,需要用到这些资料。
第一次登录后需要求先填写官网上的登录验证码和订单提交验证码,只要填写正确后,在填票过程中就一直可以使用,这也是官网的BUG,应该是他们在较正验证码后,没有让当前验证码失效,这样就只要不去刷新验证码,就可以一直使用第一次输入的正确验证码。
填写一下订票任务,主要就填写订票人资料(当然这个也是要在官网上添加过的),和订票信息,什么时候从哪到哪,从几列车等,保存完后,点开始,就则可以自动登录,找票,然后订票,订票成功后发邮件通知。
执行过程中,会时间更新执行的结果信息。
留言板功能,收集问题的反馈。
网友提供http代理,官方网站对一个IP的单位时间内访问次数据有限制,超过这个超制值IP会被封锁一段时间。
因为使用的人多,所以系统需要使用代理来向官网发送请求。
看到系统的整体内容后,再来介绍一下相关的技术
这个自动发送请求,提交数据,都依赖于httpclient4,火车票订票官方是使用ssl加密,这里是启用httpclient的ssl功能
SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(null, new TrustManager[]{easyTrustManager}, null);
SSLSocketFactory sf = new SSLSocketFactory(sslcontext);
Scheme sch = new Scheme("https", sf,443);
httpclient.getConnectionManager().getSchemeRegistry().register(sch);
大家都知道,这个官网的反映速度有时实在是惨不忍睹,所以我们也要设计一下请求等待的最长时间(30秒):
httpclient.getParams().setIntParameter("http.socket.timeout",30000);//毫秒
官方网站对一个IP的单位时间内访问次数据有限制,超过这个超制值IP会被封锁一段时间。
因为使用的人多,所以系统需要使用代理来向官网发送请求,这个代理需要支持ssl,所以先网上找到一批代理IP过来,存在一个txt文字,格式为 ip:端口\n,以下读取IP代理,并且进行速试测试
public void run(){
try {
System.out.println("-----设置代理服务器----");
String proxyFileString0 = FileUtils.readFileToString(new File(ApplicationUtils.getWebrootDir()+"/order/proxy_add.txt"), "UTF-8");
String proxyFileString1 = FileUtils.readFileToString(new File(ApplicationUtils.getWebrootDir()+"/order/proxy_enable.txt"), "UTF-8");
String proxyFileString = proxyFileString0+"\n"+proxyFileString1;
for(String proxyString : StringUtils.split(proxyFileString, "\n")){
proxyString = proxyString.trim();
if(StringUtils.isNotEmpty(proxyString)){
System.out.print("-----测试代理服务器: "+proxyString);
String[] proxyInfo = proxyString.split(":");
HttpHost httpHost = new HttpHost(proxyInfo[0], Integer.valueOf(proxyInfo[1]));
long start = System.currentTimeMillis();
if(HttpUtils.testProxy(httpHost)){
long usetime = System.currentTimeMillis()-start;
if(usetime > 10000){
System.out.println(" 不使用,响应时间太长时间:"+usetime+"毫秒----");
}else{
System.out.println(" 可使用,使用时间:"+usetime+"毫秒----");
httpHostList.add(httpHost);
}
}
}
}
System.out.println("-----设置代理服务器成功,总数:"+httpHostList.size()+"----");
} catch (Exception e) {
}
}
最后在每次请求时,选择一个代理
//设置代理对象 ip/代理名称,端口
try{
httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,ProxyHostUtils.next());
}catch(Exception e){}
每个用户在发送请求前,先从官网上读取两个验证码,一个是登录验证码,一个是提交订单验证码,一次性读取就可以了。
/**
* 读取登录验证码
* @throws Exception
*/
@Transient
public void getRemoteLoginCode() throws Exception {
File file = HttpUtils.doGetFile(OrderRunTask.loginCodeUrl+"&nocache="+Utils.getRandomString(10), cookieContext);
if(file != null){
File codeFile = new File(ApplicationUtils.getWebrootDir()+getLoginCodeUrl());
FileUtils.copyFile(file, codeFile);
}
}
/**
* 读取提交订单验证码
* @throws Exception
*/
@Transient
public void getRemoteSumitCode() throws Exception {
File file = HttpUtils.doGetFile(OrderRunTask.submitCodeUrl+"&nocache="+Utils.getRandomString(10), cookieContext);
if(file != null){
File codeFile = new File(ApplicationUtils.getWebrootDir()+getSubmitCodeUrl());
FileUtils.copyFile(file, codeFile);
}
}
每个用户可以同时订多张火车票,系统为每张火车票启动一个线程,持续的运行,直到订票成功或者是被中断。
//建立线程池
public static ExecutorService runningTaskPool = Executors.newFixedThreadPool(1000);
//启动订票任务
OrderRunTask orderRunTask = new OrderRunTask(account, orderTask);
OrderRunTaskUtils.runningTaskMap.put(orderTask.getId(), orderRunTask);
Future<?> future = OrderRunTaskUtils.runningTaskPool.submit(orderRunTask);
orderRunTask.setFuture(future);
//中断任务
OrderRunTask orderRunTask = OrderRunTaskUtils.runningTaskMap.get(taskId);
try{
orderRunTask.setStop();
orderRunTask.getFuture().cancel(true);
}catch(Exception e){
e.printStackTrace();
}
//判断是否订票成功,并且发送邮件
if(body.indexOf("45分钟") != -1){
Date now = new Date();
account.sendMail(orderTask.getQueryTrainDate()+"_订票成功",
orderTask.getQueryTrainDate() +" "+
orderTask.getFromStation()+"到"+orderTask.getToStation()+(StringUtils.isEmpty(orderTask.getTrainNo())?orderTask.getTrainNo():"")+" --订票时间:"
+DateUtils.getDateTime("HH:mm:ss", now)
);
account.setReload(true);
orderTask.setState(200);
orderTask.setRuningTime(now);
this.account.error(orderTask.toString()+": 订票成功。");
break next;
}
这也只是本人兴趣开发,不使用在商品场合,以上分享的只是这个系统的设计思想,有时间再深入讨论。
顺便附上本机(随时变动的)的一个链接地址,大家可以看看
http://125.77.229.129:7070/order.html
- 大小: 64.8 KB
- 大小: 75.2 KB
- 大小: 48.7 KB
- 大小: 64.4 KB
- 大小: 25.3 KB
- 大小: 20.7 KB
- 大小: 22.5 KB
分享到:
相关推荐
用httpclient开发的在线自动抢订火车票系统 此代码为转载 原文链接:http://www.iteye.com/topic/1119632
(1)不支持验证码自动识别 (2)不支持一次订多个票 (3)截止2012-11-06为止,程序还是好用的。
Android的HttpClient开发实例。欢迎下载学习
用httpclient实现的一个自动注册的modo
HttpClient中文文档,快速开发
(1)添加提前登录并保持在线功能 (2)添加订票成功打开浏览器的功能 (3)还是不支持多个人 (4)截止2013-01-08号之前好用
httpclient开发所必须架包
httpclient-4.0-alpha2.jar commons-codec-1.3.jar commons-httpclient-3.1.jar httpclient开发所有的包以及实例
httpclient4.5.4 开发文档 超文本传输协议(HTTP)或许是最重要的互联网上使用的协议。Web服务、网络功能和网络计算的增长继续扩展HTTP协议的作用超出用户的Web浏览器、应用数量的增加,需要支持HTTP。 尽管net包提供...
httpclient 开发需要用到的全部jiar包,主要用于http相关的开发工作。
HttpClient的使用需要三个包,分别是commons-httpclient-3.1.jar、commons-logging-1.1.1.jar、commons-codec-1.3.jar,每个包内都有API
httpClient自动接受https请求的所有证书代码,修改相应测试url,主函数运行即可
使用HttpClient必须的jar包 使用HttpClient必须的jar包 使用HttpClient必须的jar包
HttpClient 是 Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,...本文首先介绍 HTTPClient,然后根据作者实际工作经验给出了一些常见问题的解决方法.
本文 中 的 选 课 辅 助 系 统, 通 过 采 用 Fiddler 与 Chrome的开发工具获取浏览器与教务系统的 Web 应 用程序的数据接口 ,实现对某学院现有的教务系统的 选课功能扩展 。 本系统将重点针对学生选课业务进 行...
httpclient4之百度模拟登陆,回复与58同城自动登陆
模拟登陆方正系统,在此基础上可以做开发类似课程格子之类的软件供个人或者多人之用
HttpURLConnection与HttpClient的区别: HttpClient是个很不错的开源框架(org.appache.http),封装了访问http的请求头,参数,内容体,响应等等,使用起来更方面更强大。 HttpURLConnection是java的标准类,可以...
全栈自动化测试实战 基于testng,httpclient,selenium.appium 书本上的东西
httpclient