真是很惭愧。看到网上那多哥们如何如何用自己写的工具、脚本,买到了回家的车票至少还是都是卧铺的。但是我水平不行,只买到了硬座的(已完成支付,收到了12306的短信通知但未换纸质车票)。既然只买到硬座的而以还有啥好说的呢?更何况这是博客园首页啊!其实我只想说我其实也做了不少工作,可能算是技术不行、也可能是绕了很多弯路、还有可能就是12306或95105105虽然很烂但其实他们也是在不断的改进的,今天找到的方法说不定明天效果就不好。
首先讲讲做了哪些工作:
12306.cn
第一次访问了该网站之后我就想应该可以写一个自动化的工具,可以自动帮我去进行查票、订票。最开始的时候想的前面几步都是手工实现的,然后通过构造发送最终的订票数据。来模拟提交。但不是很理想,虽然把本地所有的cookie信息都模拟提交了但还是返回不了正确的订票信息。
于是就想写WinForm之类的工具,遇到了验证码。考虑过用人工的方式但还是想着如果能够破解图形验证码的话效果应该更好。无奈花了一、两天的时间来搞验证码,做一过比如把图片信息变为0和1分布的矩阵,通过查找相对位置的办法来识别,但是识别效果并不好,因此放弃。
最近这两天在网站方面已经不考虑再写什么工具了,注册了三个账户,把要买的人员全部加为联系人,在查票的时候挂上如下简单的脚本,进行自动刷新而以。
setInterval(" this.document.getElementById('main').contentWindow.document.getElementById('submitQuery').click();",10000)
95105105
虽然电话订票的渠道知道的时间要比网上稍晚点,但网上看了一些文章好像用电话订票的成功率要高点似的。刚开始想的也是自动来实现的,但是订票环节中加了个验证码,全流程的自动化暂时是行不通了。但是由于之前接触过Skype相关的API,因此还是写了一个简单的外挂,进行自动化重拨和身份证输入等功能。写这个外挂过程中我还特决购买了800多分钟的skype套餐(还有一半未使用完)。
Skype通话录音与尽快重拨代码(需要安装Skype4COM)
- /// <summary> /// 忙重拨
- /// </summary> /// <param name="phoneNum">电话号码,例如:01095105105</param>
- public void ReDial(string phoneNum)
- {
- try
- {
- objSkpe = new Skype();
- objSkpe.Attach(7, true);
- objCall = objSkpe.PlaceCall(phoneNum);
- //设置声音文件输出目录
- string outPutFolder = System.Environment.CurrentDirectory + "\audio\"
- if (!Directory.Exists(outPutFolder))
- {
- Directory.CreateDirectory(outPutFolder);
- }
- string waveFile = outPutFolder + phoneNum + "_" + DateTime.Now.ToString("yyyyMMdd_hhmmss") + ".wav"
- //录音
- objCall.set_OutputDevice(TCallIoDeviceType.callIoDeviceTypeFile, waveFile);
- //WriteLog("拨号中...");
- TimeSpan startTime = new TimeSpan(DateTime.Now.Ticks);
- //循环直到通话中
- while (objCall.Status != TCallStatus.clsInProgress)
- {
- //判断拨号超时
- if (objCall.Status == TCallStatus.clsRouting)
- {
- Thread.Sleep(1000);
- TimeSpan stopTime = new TimeSpan(DateTime.Now.Ticks);
- TimeSpan val = stopTime.Subtract(startTime).Duration();
- if (val.TotalSeconds > 30)
- {
- objCall.Finish();
- }
- continue
- }
- //忙或关闭等各种状态重播
- if (objCall.Status == TCallStatus.clsBusy
- || objCall.Status == TCallStatus.clsFailed
- || objCall.Status == SKYPE4COMLib.TCallStatus.clsFinished
- || objCall.Status == SKYPE4COMLib.TCallStatus.clsCancelled
- || objCall.Status == SKYPE4COMLib.TCallStatus.clsEarlyMedia
- || objCall.Status == SKYPE4COMLib.TCallStatus.clsRinging
- )
- {
- //如果是忙音,则需要先挂断再重拨
- if (objCall.Status == SKYPE4COMLib.TCallStatus.clsEarlyMedia || objCall.Status == SKYPE4COMLib.TCallStatus.clsRinging)
- {
- objCall.Finish();
- }
- //WriteLog("忙重拨...");
- Thread.Sleep(1000);
- ReDial(phoneNum);
- }
- }
- // WriteLog("通话中...");
- }
- catch (Exception exp)
- {
- //WriteLog("Error:" + exp.Message);
- }
- }
虽然流程自动化系统比较难实现,但其实我也在这方面做了一些努力,比如动用了微软的SpeechSDK来参与我的抢票工作,以下是调用SppechSDK识别声音到文本的结果展示。
但是由于目前还未找到直接将Skype的流转为SpeechSDK可以识别的流,因此该方案目前暂无进展。
效果:
12306.cn 本文标题所指的硬座其实写的工具都没有派上用场,最后还是通过“人工”的方法来订到的,可惜提交了不少于50次的卧铺订单但还是无法成功订到。
95105105 开发了不少功能,但是最实是实用的还是自动重播那一项,该渠道于昨天(1月18日)帮一朋友买到了临客的卧铺,也还算是聊以慰籍。本来今天还想给我自己订的无奈很不给力两个Skype从7:58开始拨到8:30才拨通不说,好几次都确认订票信息了,系统直接给我提示“系统繁忙,订票请按1”,崩溃了。。。。(不更早一点拨号是因为之前发现7点多拨的号到8点以后还是订不了最新预售期内的票,网站好像也有这个问题。他是根据登录时间来定的而不是当前时间,所以早拨也没用。)
总结一下:
网站和电话其实这两个方向我都了相应的探索但基本都属于无功而返,反思这次做为一个程序员的的抢票行动,我觉得有以下几点是需要考虑的:
1. 开发工作脱离目标
目标虽然很清晰,但是在实际开发过程中很容易进了死胡同里,特别是感觉如果解决了很有成就感的技术问题。当然还有可能是由于技术水平有限,应该有高手早就解决了我遇到的这些问题了。
2.少即是多,准备的东西太多,抢票时手忙脚乱的。看看我的工作台快照
无论怎样。我觉得此次抢票行动比起在车站排除买票,还是意思的多的。最后,祝大家都能买到中意的车票平安回家,新年快乐!
原文链接:http://www.cnblogs.com/wuhuacong/archive/2011/11/22/2259128.html
【编辑推荐】