标题: VBS也玩验证码识别
作者: Demon
链接: https://demon.tw/programming/vbs-authcode.html
版权: 本博客的所有文章,都遵守“署名-非商业性使用-相同方式共享 2.5 中国大陆”协议条款。
这几天不是在学Python嘛,怎么还老写VBS的东西。
其实我学Python有两个原因,一是很多开源的BT下载软件是用Python写的,哪天没事可以改改源码做做弊什么的;二是以前无意中看到《python验证码识别之Discuz》的系列文章,顿时感到Python之强大,验证码都能识别,想做什么不行?
几天下来学了点Python的皮毛,于是迫不及待的看了一下《python验证码识别之Discuz(一) 》,发现依然看不懂。并不是看不懂语法,而是看不懂算法。PIL库固然强大,但是光靠库本身还是无法识别验证码,还得加上图形算法。可见语言什么的都是浮云,会算法才是王道。
于是Google了一下验证码识别的原理,自己尝试着用VBS识别晨光BT(该网站需要IPv6网络才能访问)的验证码,发现并没有想象中的困难。之所以选择晨光BT的验证码,是因为它本身比较简单,再加上我还有它的源码,识别起来会相对容易些。
鉴于大部分网络依然是IPv4,我把生成验证码的页面放到了博客的测试目录中,可以点击这里查看。
用PS放大以后可以知道,验证码只是简单添加了些杂点。首先把黑色边框去掉,然后把杂点去掉(颜色改成背景色白色)。
'加载图片 Set Image = CreateObject("WIA.ImageFile") Image.LoadFile "authcode.png" Width = Image.Width Height = Image.Height Set Vector = Image.ARGBData '去除边框 For i = 1 To Vector.Count If (i - 1) \ Width = 0 Or _ (i - 1) \ Width = Height - 1 Or _ i Mod Width = 0 Or _ (i - 1) Mod Width = 0 Then Vector(i) = &HFFFFFFFF End If Next '去除杂点 For i = 1 To Vector.Count If Vector(i) <> &HFF000000 Then Vector(i) = &HFFFFFFFF End If Next
接下来要确定单个验证码的范围,即能把单个验证码框起来的最小矩形的对应坐标。
'获取横向范围 Set Range = CreateObject("WIA.Vector") For i = 1 To Width For j = i To Vector.Count Step Width If Vector(j) <> &HFFFFFFFF Then Range.Add i Exit For End If Next Next '写到这里肚子饿了,感谢怒云提供的算法 '先将Vector转换成String str = Range(1) For i = 1 To Range.Count - 1 If Range(i+1) - Range(i) < 3 Then str = str & "," & Range(i+1) Else str = str & ";" & Range(i+1) End If Next '然后再分组 x = Split(str,";") For i = 0 To UBound(x) authcode = authcode & GetCode(Split(x(i),",")) Next
x数组保存了6个单独验证码的横向坐标,遍历数组,调用GetCode函数识别验证码。下面是函数的关键算法。
'获取横向范围对应的纵向范围 min = 20 max = 1 For i = xn(0) To xn(UBound(xn)) For j = i To Vector.Count Step Width If Vector(j) <> &HFFFFFFFF Then y = (j - i) / Width If y < min Then min = y If y > max Then max = y End If Next Next '获取单个验证码范围内的ARGB For i = min To max For j = xn(0) To xn(UBound(xn)) code.Add Vector(i * Width + j) Next Next '与标准的验证码对比 For Each item In Standard Dim difference : difference = 0 For i = 1 To code.Count '这里数组可能会越界,所以上面要On Error Resume Next If code(i) <> Standard(item)(i-1) Then difference = difference + 1 End If Next oDic(difference) = item Next '筛选出最匹配的 min = 80 For Each item In oDic If item < min Then min = item Next
先求出单个验证码对应的纵向范围(横向范围已经当成参数传递),然后把范围内的点的ARGB值和标准验证码(standard字典变量)对应点的ARGB值做比较,不同的话difference加1,最后选出difference值最小(即最匹配)的返回。
那就有一个问题了,标准验证码的值怎么得到?这就要靠你的PS功底了。
用PS将单个验证码切片并除杂以后获得,最笨的方法是一个个人工写。比如上图中的W标准值依次为&HFF000000,&HFF000000,&HFFFFFFFF……当然傻子才会这么做,写个VBS完成。
Set img = CreateObject("WIA.ImageFile") img.LoadFile "w.bmp" Set v = img.ARGBData For i = 1 To v.Count out = out & "&H" & Hex(v(i)) & "," Next out = Mid(out,1,Len(out)-1) WScript.Echo "Standard(""w"") = Array(" & out & ")"
假设上面的W切片后保存为w.bmp,上面的程序将输出对应的标准值数组(前提是你的PS过关,保证切片是标准)。虽然上面的脚本可以节省标准值数组的时间,但是切片的工作还是得人工完成(虽然PS也支持VBS自动化,不过等我学会了人工已经完成了),要知道一共有25个字符啊!写这个程序的绝大部分时间都耗在这个上面了。。。
第一次写那么长的文章(主要是代码长),我知道不会有几个人能看到这一行,看到这一行也不一定看得懂。因为我知道,看别人的程序常常比自己写程序还要困难。最后不要脸的说一句,我果然是天才。
源码下载:[download id=50]
赞赏微信赞赏支付宝赞赏
随机文章:
很有创意啊
写得真是不错啊。。。学习了
借鉴了
借鉴你的代码 我还真的把西贴图片里的报价处理出来了 谢啦
确实不要脸。。。
图片不见了!
可以分享下源码吗,多谢了
这么多年过去了 从看得一头雾水不明觉厉到现在回头看终于是变成了简单代码 果然还是佬写的博客和代码看得最舒服