由于经常需要登录某系统进行测试,但系统里有验证码每次都要进行输入感觉稍微有点繁琐。为此打算采用验证码自动识别的技术来实现。据我所知,目前识别验证码主要可以有以下方式进行解决:
其中速度上ocr和机器学习去识别验证码的速度是最快的,但ocr需要验证码的字符很规范才能进行识别,否则也是识别不了的。而我目前想识别类似这样的验证码,那么ocr的方式去识别则准确率会非常低的
由此,遍萌生了采用机器学习的方式来处理此验证码,并决定采用tensorflow框架来进行识别
在写了自己的训练模型后发现其识别率并不高,于是在网上搜了下大佬们是怎么处理的,于是发现了此框架https://github.com/kerlomz/captcha_trainer
于是自己尝试了一下后,识别上面的验证码的准确率达到了1.0,以下为主要的操作步骤,特此进行记录
为了训练验证码,那么得要先将验证码生成出来。
先分析上面的验证码可能的字符:0123456789+-x÷?=
为了训练的方便先进行一次转码:0123456789abcdef
即数字不变,特殊符号+-x÷?=依次修改为abcdef
然后再自己写个脚本进行生成,我这里一次生成10万张验证码进行训练。(生成验证码的代码在这里就贴出来了,不同的情况不同的写法)
其文件名遵循如下法则即可:真实值_UUID.jpeg, 如此处的:1a7fe_0779a021f919422cbe603de6bc4ce590.jpeg
将其生成到某个目录即可,如此处的:D:/temp/obj
训练的步骤参考https://github.com/kerlomz/captcha_trainer的readme.md就可以了
其主要步骤主要分3步:
由于上面的步骤比较简单,这里就不贴出来了,其github上面也有比较详细的说明,具体的可以参考此项目的readme.md
通过我的个人实践强烈建议训练时采用tensorflow-gpu来进行训练,因为我也用cpu来进行训练测试过,实在是太慢了而且还很费电!用cpu训练6万张用了一下午的时间才训练好,而gpu只用了3分钟就训练完毕了。
另外在安装CUDA与cuDNN时注意版本的选择,版本太高的话,可能会导致与tensorflow-gpu的版本不兼容
还有就是,请使用python3.6版本,目前的tensorflow还不支持3.7版本的python。如果本地已经安装了python的其他版本了的话,可以通过安装anocada进行处理,如果没有科学上网的话,为了提高下载速度,需要将anocada配成国内的anocada源,具体的自行百度即可,其用法与Virtual Environment类似
部署时采用https://github.com/kerlomz/captcha_platform项目
当上面的训练完毕后,会在out目录生成两个文件,按照官方的操作步骤将生成的文件copy到captcha_platform对应的目录即可。
然后就是安装依赖和启动项目了。安装依赖时此项目直接安装tensorflow即可,没有必要安装tensorflow-gpu版本。
如果在windows上安装依赖,需要安装 vc++ 4.0,否则可能会报错。
当依赖安装一切就绪后,选择platform项目中的一个server进行启动就可以了。如我这里的:
执行
python tornado_server.py
然后就可以啦
对于测试其captcha_platform的readme.md中也有比较具体的描述,如果是用http服务启动的,调用http接口即可。
先将打算解析的图片转为base64,然后再传入到接口中就好了
为了测试方便,可以直接在百度上搜一个在线base64图片编码的工具进行转码也可以自己编码进行操作
也可以像我这样写一个python脚本进行测试,对某个目录下的所有文件进行一次测试:
import base64
import json
import os
import re
import hashlib
import time
import requests
import io
from PIL import Image
path = "D:\\temp\\obj007"
url = "http://localhost:19952/captcha/v1"
def img_test():
error_count = 0
for i in os.listdir(path):
right_str = i.split("_")[0]
print(i + "->" + right_str)
with open("D:\\temp\obj\\" + i, 'rb') as f:
base64_data = base64.b64encode(f.read())
s = base64_data.decode()
print('%s' % s)
data = {
'image': s,
}
r = requests.post(url, headers=headers, data=data)
res_json = json.dumps(r.json())
print(res_json + " ->" + r.json()['message'])
if (right_str == r.json()['message']):
print("ok!")
else:
error_count = error_count + 1
print("!!!!!!!!!!!" + str(error_count))
当然,最快的还是直接在postman里测试,不管用哪个,只要自己开心就好,哈哈
我这里就直接这样操作了,在线转:
然后将转码后的base64复制过来,发送到接口中就可以啦
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
如在postman中这样测一下:
其中返回的message就是自动识别后的值啦。如这里的:
{
"message": "54d6fe",
"code": 0,
"success": true
}
54d6fe再按照之前定义的规则转一下就变成了:54÷6=?