2008年10月29日星期三

如何用QTP解决图片验证码(解析QuickTest文本识别机制)?

大家在使用QTP进行自动化测试的过程中经常会遇到图片验证码的问题——大家所关心的就是如何解决此类问题。
这里我们首先要去了解为什么会有图片验证码。其实验证码的本质作用就是防止有人利用工具(灌水机、注册机,当然也不小心包括了我们的自动化测试工具)恶意猜解登陆或者不停的注册和灌水的。因此如果我们完全寄希望于通过GUI识别来获取内容是不切实际的——先打好预防针,免得读者希望太大,失望更大,呵呵!
下面说说验证码的解决思路:

在QTP9.5中,对象识别能力有了进一步改善,其中针对文本识别方面进行了优化,引入了ABBYY公司的OCR解决方案——这个相关的功能体现在QTP菜单的“Tools–>Options–>General–Use text recognition mechanisms in this order”里,详细内容后面会有具体介绍。

先来看看ABBYY是何许公司,登录他们的官方网站可以看到一段相关介绍:“ABBYY是世界OCR(光学字符识别)、ICR(手写体识别)和语言软件的领航者。ABBYY 致力于人工智能(AI)和语言软件开发。提供全套文档识别,转换和数据捕获技术的产品解决方案。”如果你使用过图像文档转换的软件,一定会听说过FineReader OCR Professional ,其实它就是ABBYY公司的产品,用官方的说法就是“将通过扫描仪、MFP 或数码相机生成的图像快速转换为可编辑和可搜索的电子格式,而且识别率很高”,说白了就是可以借助它先进的OCR机制“读”出图片里的文本内容,并转换为PDF之类的文档。
有了ABBYY这么强大的背后支持,QTP自然底气十足,那么QTP到底如何以OCR机制识别文本呢?我们首先先了解一下什么是OCR。
打开“百度百科_OCR”,它的说明:“OCR(Optical Character Recognition,光学字符识别),是属于图型识别(Pattern Recognition,PR)的一门学问。其目的就是要让计算机知道它到底看到了什么,尤其是文字资料。 由于OCR是一门与识别率拔河的技术,因此如何除错或利用辅助信息提高识别正确率,是OCR最重要的课题,ICR(Intelligent Character Recognition)的名词也因此而产生。而根据文字资料存在的媒体介质不同,及取得这些资料的方式不同,就衍生出各式各样、各种不同的应用。”这里有个关键词:“正确率”,也就是“识别率”——既然不能够总是100%,我们自然不可能完全寄希望于通过QTP能够每次100%正确的去识别图片里的文本。尤其是“道高一尺魔高一丈”的今天,验证码加入了大量的干扰素,如扭曲、变形、错位、随机背景花纹,给OCR识别增加了很多难度——本来就不希望被软件识别到嘛。

了解了OCR之后,我们再来看看QTP对应的这个设置。如前面所说,通过QTP菜单的“Tools–>Options”选中到“General–Use text recognition mechanisms in this order”,这里的四个选项就是对应的不同设置。我们看看帮助的描述(我做了翻译):
=================================
使用文本识别机制

指定QTP在采用 “文本”或者“文本区域” 的 检查点或输出值 的步骤时,捕获文本内容所使用的文本识别机制。
以下有三种识别方式:
1、先使用Windows API,再使用OCR(默认)。
指示QTP首先尝试以基于Windows API的机制从对象上直接获取文本内容。如果未获取到文本(比如,文本属于图片的一部分QTP就会使用OCR的机制尝试获取这段文本。
强烈建议在使用中日韩(象形文字)、英的语言环境下采用这个设置。

2、先使用OCR,再使用Windows API。
指示QTP首先尝试使用OCR机制从对象上去获取文本。如果未获取到文本QTP就会以Windows API的机制去获取文本内容。

3、仅使用Windows API方式。
指示QTP仅采用基于Windows API的机制从对象上获取文本内容。

4、仅使用OCR的方式。
指示QTP仅采用基于OCR的机制从对象上获取文本内容。
在使用Windows Vista要使用这种方式。



如果用文本区域输出值(Text Area Output)试图去获取值的时候QTP会提示你“The object you selected does not support this operation(你所选择的对象不支持此操作)”。
那么,如果改用文本输出值(Text Output)又会怎么样呢?结果又让人失望了,它提示“Cannot Retrieve text for this object(无法从这种对象上获取文本)”!
这下晕了,好不容易找到了取值方式,却两种方式都不支持。
怎么办呢?………………既然此路不通,咱们就绕道而行吧!

仔细看看上面那张图,我们可以看到,其实QTP是支持在Standard Windows(标准Windows)对象中使用文本区域输出值(Text Area Output)的,既然如此,我们何不让QTP在这个时候卸掉web插件,以windows方式去抓取这个对象呢?
有了解决的思路,一切就好办了——我们做两个脚本就能解决这个问题。

下面是具体的解决步骤:
1、先单独录制一个不加载web插件的脚本,这个脚本只做一件事——就是以Text Area方式去取图片验证码中的值。


对应的代码就是:
Window("Microsoft Internet Explorer").WinObject("Internet Explorer_Server").Output CheckPoint("Internet Explorer_Server")

从上面代码我们可以看到,我强迫让QTP把浏览器当做一个普通的Windows对象来识别,而不是一个Web对象去识别。
2、把这个脚本的Action改个易理解的名字,就叫GetChar吧,然后在这个Action上面加一个Action Output parameters,参数名叫AuthCode。
下面有图能看到。
3、把这个脚本保存下来,脚本就叫GetCodeText吧。然后关掉QTP
4、现在再打开QTP,做第二个脚本。记得这一次在插件管理器里记得要勾选上对应的Web插件了!录制一段注册论坛用户名的脚本,并把其中验证码的输入部分参数化,代码如下:

Option Explicit
Dim myCode
SystemUtil.Run "C:\Program Files\Internet Explorer\IEXPLORE.EXE","","C:\Documents and Settings\Administrator","open"
Browser("Browser").Page("Page").Sync
Browser("Browser").Navigate "http://bbs.yuzi.net/CreateUser.asp"
Browser("Browser").Page("互动交流平台 - Powered By BBSXP").WebEdit("UserName").Set "songfun"
Browser("Browser").Page("互动交流平台 - Powered By BBSXP").WebEdit("UserEmail").Set "songfun@51testing.com"
Browser("Browser").Page("互动交流平台 - Powered By BBSXP").WebEdit("VerifyCode").Click
RunAction "GetChar", oneIteration,myCode
Browser("Browser").Page("互动交流平台 - Powered By BBSXP").WebEdit("VerifyCode").Set myCode
Browser("Browser").Page("互动交流平台 - Powered By BBSXP").WebList("PasswordQuestion").Select "最喜欢的老师"
Browser("Browser").Page("互动交流平台 - Powered By BBSXP").WebEdit("PasswordAnswer").Set "songfun老师"


注意:在代码中有一句RunAction,其实是我在这里做了一个“Call to Copy of Action”动作,把刚才那个GetCodeText脚本中的名叫GetChar的Action给加载进来了(强调下,必须是以Action嵌套方式而不是并列方式来调用的)。
具体代码和形式如图:



5、脚本做好之后,点击Run,看看它的效果。如图:

没有评论:

发表评论