用httpclient开发的在线自动抢订火车票系统(铁老大不给力,哥给力)
前两天女友要在线订火车在票,一直都没有办法订到票,最后没办法,便给她写了个自动抢票的脚本,可周边的朋友听她说通过软件订到票了,都先后向她要软件,可原来的脚本只是基于控制台输入,这样给别人也没法用,兴趣一起,就花了一天的时间做了个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); httpclient.getParams().setIntParameter("http.socket.timeout",30000);//毫秒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 */@Transientpublic 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 */@Transientpublic 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;}