一直想不明白,公司内网的一个会议室系统为啥需要验证码登陆?难道就为了防止员工用工具刷会议室?(滑稽笑😌)
并且既然做了验证码,居然还用的最原始的数字+字母形式,除了文字颜色,验证码图片中一点干扰信息也没有。。。
这也就给了我一个可乘之机😀
废话不多说,用十分钟搞定这个验证码吧!
验证码识别工具选取
一般而言,为了方便自动化测试,开发都会单独提供一个接口或者万能验证码。但本次是为了抢会议室,验证码只能靠自己搞定了。
识别验证码的过程其实就是图像识别,主要是ocr文字识别技术。市面上有许多免费的ocr引擎以及API,能够识别多种语言,不过一般识别率不是很高,若要追求识别率,甚至还有收费的人工打码平台。
对付公司的这种简单的验证码,用开源的ocr引擎就够用了。本次选用的是Google爸爸出品的ocr引擎----Tesseract,不仅功能强大而且使用简单,并且还是开源的。
Tesseract安装与使用
1、安装
安装过程比较简单,直接参看官方文档即可:安装tesseract方法
说明:windows下安装tesseract后需要将tesseract.exe路径加入系统path环境变量。
2、使用
tesseract的使用方式一般有两种:可以动态调用libtesseract或者直接使用tesseract.exe程序。本次为了方便偷懒,直接采用后者。使用方式如下:
#打开cmd窗口,直接使用以下命令
tesseract c:\code.png c:\result -l eng
以上命令表示用tesseract识别c盘目录下的code.png的内容,并将识别的结果输出到result.txt中,识别的语言为english。
获取验证码图片并识别
有了工具,就只差需要被识别的验证码图片了。
一开始准备直接抓取验证码的链接直接下载一份验证码图片,但后来发现不行,每次访问验证码的url都会动态生成新的验证码😓。
所有只有两种方法获取验证码图片
1.从cookie中抓取
2.直接截图
为了方(偷)便(懒),本次使用第二种截图的方式。
但采用截图获取验证码图片的话就面临一个问题,如何只截取含验证码的部分区域呢?
这个就得借助selenium的控件属性以及python的Image库了。
说明:python使用Image需要单独安装PIL
步骤:
1、使用selenium截取全屏图片
2、使用selenium定位到验证码控件,通过元素的.location属性获取该控件的绝对坐标,计算出验证码在屏幕的区域。
3、根据步骤2中的坐标,使用Image工具对步骤1中的全屏截图进行切割,最终得到只包含验证码部分的图片
4、剩下的就交给tesseract去识别了
实现代码(部分):
import os,Image
from selenium import webdriver
path = os.path.dirname(os.path.realpath(__file__))
#全屏截图
driver.get_screenshot_as_file(path + '\screenshot.png')
#获取验证码元素位置
element = driver.find_element_by_class_name('login_code_img')
left = int(element.location['x'])
top = int(element.location['y'])
right = int(element.location['x'] + element.size['width'])
bottom = int(element.location['y'] + element.size['height'])
#通过Image处理图像
im = Image.open(path + '\screenshot.png')
im = im.crop((left, top, right, bottom))
im.save(path + '\code.png')
#执行识别操作
cmd = "tesseract %s\code.png %s\code -l eng" % (path, path)
os.system(cmd)
#读取最终的结果
f = open(self.path + "\code.txt")
code = f.read().replace(" ", "").replace("\n", "")
f.close
补充说明
通过以上两步操作就以及完成验证码的识别了。不过实现比较粗糙,为了提升识别率还可以做更多,比如:
- 将验证码图片进行二值化处理,提升识别率
- 对tesseract进行识别训练,让其更加智能化。
- 对于识别出的结果做一些判断,比如验证码位数不对或者登陆失败,就刷新页面继续识别。多用几次异常处理提升登陆的成功率
####项目源码
解决了以上问题,剩下的就是简单的控件操作了。除了切换frame窗口以外,基本没遇到其它问题。
源码:https://github.com/liangqiangWang/MRHelper