z007 如何编写程序实现自动进行上海汽车牌照拍牌
作者:学哥
发布时间:2017-2-20
在上海的人都知道,上海的汽车牌照是多么的难以获得,现在只能通过参加网上拍卖的方式获得,下面来探讨一下如何通过编写程序的方式进行自动拍卖,减少人为的失误因素。当然了,由于神奇的验证码每个月都会变化,期望通过程序确保百分之百能够拍得,是不太可能的,我们这里仅仅是探讨让程序来代替人工的方式尽量提高一些拍中率。
需求分析
首先,要研究一下上海车牌网上拍卖的流程和规则。
拍卖流程规则:
1.使用事先获得的账号和密码登陆拍卖网站。
2.10点半到11点之间为第一阶段出价,出价不能超过警示价,当然一般人都是直接输入警示价,输入价格后点击出价按钮,弹出验证码输入窗口,根据验证码提示信息输入验证码,点击确定按钮,完成出价。
3.11点到11点半之间为第二阶段出价,第二阶段可以出价2次,每次出价的价格范围不能超过当前价格的增加300,输入价格后点击出价按钮,弹出验证码输入窗口,根据验证码提示信息输入验证码,点击确定按钮,完成出价。
来看一下竞拍的网页是什么样子的:
竞拍规律:
1.一般来说第一阶段出价没有难度,关键在于11点29分40秒之后的出价。
2.出价过早,会被后面的更高出价击败,出价过晚,可能无法进入竞价队列,从而超时失败。
3.一般的方法是伏击法,也就是在29分40秒的时候增加700左右,到29分55秒之前,加入价格已经增长到范围之内,则立即出价,如果价格未能增长到范围之内,则最晚29分56秒必须出价,否则可能超时。
需求分析:
第一步的网站登录和第一阶段的出价,非常简单,也不会失误,没有必要采用程序。
重点在于第二阶段的出价,而且基本上只有一次出价机会,所以我们只需要实现以下功能:
1.时间到达11点29分30秒的时候,通过程序自动识别【目前最低可成交价】,例如80600。
2.根据最低成交价,增加一个预估加价值,例如900,得到出价价格81500,填写到价格输入框,点击出价按钮。
3.验证码窗口弹出后,等待3秒钟,让验证码出现,截取验证码部分屏幕形成图片,将图片中的验证码进行识别。
4.在验证码输入框中输入验证码,等待价格到达范围,或者时间到达11点29分56秒,点击确定按钮。
其中最关键的是第3步识别验证码部分,鉴于每个月的验证码的样式都会变化,期望完全采用程序来识别是有非常大的技术难度的,这里我们只讨论采用变通的方式来实现“半自动化”的程序识别。
程序设计思路
考虑到需要模拟人工操作,例如输入数字,点击按钮,截取屏幕图片,可以采用java类库 java.awt.Robot 来实现。
识别最低可成交价,需要利用开源的ocr工具包tesseract-ocr来实现。
识别验证码,可以利用网上一些打码平台来实现,原理是去网上找到这些专门进行验证码识别的平台,注册登录后,进行充值,然后下载相应的开发工具包,然后利用工具包的类库写调用代码,将验证码图片通过网络传送到打码平台,打码平台通过人工网络识别之后,传回验证码字符串。
程序主流程如下:
程序每秒循环一次,判断系统当前时间是否到达11点29分30秒
如果到达时间,则开始执行以下动作:
截取最低可成交价的数字区域范围图片,通过tesseract-ocr识别出价格数字
将价格数字增加一个预估加价值,得到出价价格数字
通过robot.mouseMove(x,y)将鼠标移动到价格输入文本框范围内
通过robot.mousePress(InputEvent.BUTTON1_MASK)和robot.mouseRelease(InputEvent.BUTTON1_MASK)让鼠标点击一次,让输入光标出现在价格文本输入框中
将价格数字分解为5个单独的数字键,通过robot.keyPress(keycode)和robot.keyRelease(keycode)让键盘输入数字键
通过robot.mouseMove(x,y)将鼠标移动到出价按钮范围内
通过robot.mousePress(InputEvent.BUTTON1_MASK)和robot.mouseRelease(InputEvent.BUTTON1_MASK)让鼠标点击一次,完成出价动作
通过robot.delay(seconds)等待3秒种,等待验证码窗口加载完成
截取验证码窗口显示范围图片,调用打码平台接口,获取验证码字符串,可能需要10秒左右
通过robot.mouseMove(x,y)将鼠标移动到验证码输入文本框范围内
通过robot.mousePress(InputEvent.BUTTON1_MASK)和robot.mouseRelease(InputEvent.BUTTON1_MASK)让鼠标点击一次,让输入光标出现在验证码文本输入框中
将验证码分解为4个单独的数字键,通过robot.keyPress(keycode)和robot.keyRelease(keycode)让键盘输入验证码
进入一个循环程序,每秒循环一次,循环内部进行判断:
截取最低可成交价的数字区域范围图片,通过tesseract-ocr识别出价格数字
假如该价格已经大于等于前面输入的出价价格,则点击确定按钮
或者假如系统当前时间已经大于等于11点29分56秒,则点击确定按钮
点击确定按钮:通过robot.mouseMove(x,y)将鼠标移动到确定按钮范围内,然后通过通过robot.mousePress(InputEvent.BUTTON1_MASK)和robot.mouseRelease(InputEvent.BUTTON1_MASK)让鼠标点击一次,完成确定动作
程序实现
由于程序较长,限于篇幅,下面只列出一些关键性的代码。
截取最低可成交价的数字区域范围图片,通过tesseract-ocr识别出价格数字:
这是调用函数,参数是最低可成交价的数字区域范围,左上角在屏幕的坐标,以及区域的宽度和高度
截取屏幕图片,采用java.awt.Robot.createScreenCapture方法来实现
截取的图片使用BMPWriter类库来实现,这个就不贴了,大家可以搜索BufferedImage如何写到文件中
然后调用tesseract.exe工具包命令行来识别图片中的价格数字
至于如何使用tesseract-ocr这个就不做具体说明了,其中的难点在于字库训练,也就是让识别程序先要进行训练,掌握这里的图片里面文字的特征,从而能够准确识别出图片里面的数字文字。
具体训练方法和使用方法,可以参考这个网页教程:http://blog.csdn.net/yasi_xi/article/details/8763385
等待识别完成之后,从结果文件中读取出最低可成交价的数字。
移动鼠标和点击鼠标:
输入价格:
点击出价按钮:
识别验证码:
截取验证码区域部分图片就不做说明了,和之前的截取最低可成交价的范围图片的方式一样,只是区域范围不同而已。
下面仅以某打码平台为例说明,注意不同的打码平台调用接口的方式可能不一样:
其实还可以同时调用多个打码平台,看谁先返回验证码结果就采用谁,可以减少获取验证码的花费时间。
输入验证码:
点击确定按钮:
测试验证
由于正式的拍卖网站只有到每个月拍卖的那一天才真正开放访问,所以平时是无法进行测试的,不过我们可以到利用一个模拟网站进行测试,www.51hupai.com 访问这个网站,点击最上方菜单【51《全真模拟》】,可以模拟运行,从而可以启动我们编写的程序进行测试。
可以将一些常量参数做成配置txt文件,让程序运行的时候读取这些参数,这样可以让程序更灵活,不用频繁修改编译代码。
调整参数中的启动时间,以及坐标值,高度宽度值,加价值等等,来适应模拟网站,从而可以完成测试。
这样,到正式拍卖的时候,只需要调整参数就可以完成自动化竞拍了。
发散探讨
由于打码平台背后的实质也是通过人工网络进行识别,因此所需的时间基本都在十多秒,因此不能算是完全的程序化,也就无法利用机器的性能进行瞬间识别,在现有的竞拍规则下,没有非常高的实时性,是不能实现完全百分之百的拍中率的。
也许,未来等待图像识别技术发展到更先进,或许可以采用其它更快更高识别率的平台来进行验证码的识别。
就算可以实现这一点,但基于竞拍规则的时间窗口极短效应,可能也无法实现最终的目标,但是还可以采用创建多个虚拟机的方式,部署多个账号同时竞拍,将预估价格进行区间分段进行伏击的办法,也是可以提高拍中率的。
道高一尺,魔高一丈,技术这条路真的永无止境。所以,我们还是祈求运气再好一点吧。