注:百度又一次更换验证码,下面的方法已失效.
但是使用本文介绍的方法可以识别所有普通验证码,即使使用了干扰技术.

建议大家不要在验证码识别上投注过多的精力,
毕竟模拟编程最主要是为使用电脑带来方便,而不是去对付别人的网站.
而验证码识别也只是模拟精灵强大功能的很小的一个部份.

声明:
写这篇文章的目的纯为研究模拟机器人编写技术,
严禁用本文介绍的方法、代码滥发垃圾信息,否则后果自负、概与本站无关。

前些时候我写了篇《教你轻松识别验证码》以百度贴吧为例讲解了如何编写能识别验证码的机器人。
原文见:http://www.yhhe.net/bbs/dispbbs.asp?boardID=4&ID=67&page=1

这个程序使用的人太多。百度这几天再次更换了新的验证码,添加了大量的干扰点。
我看了一下,大致的把新的识别方法在这里写一下,下面的方法比前的速度快了几倍
呵呵,[模拟精灵2005] 是一个遇强愈强的软件 :) 。

当然公开了这个方法以后百度应当会再次更改验证码,所以不保证下面的代码与程序长期有效。
但是掌握下面的方法,可以很轻松的破解几乎所有社区的验证码了,如果不是自已拥有服务器的话很难再做出更变态的验证码。

运行下面的程序,需要 模拟精灵2005 v4.32 以上版本


贴吧验证码上的字符是黑色的,而杂点却是彩色的(真不知道他们怎么想的,呵呵。。。。)
这样程序很复杂,破解反而很容易了,只要把彩色去掉,基本上干扰点就去除了大半。如下:
img:bpp(1); -- 把颜色位数转换到1位,也就是黑白图片了
img:bpp(24); -- 再把 颜色位数转换还原到24位(jpg需要24位)
经过上面的转换,彩色的干扰点已全部消失.这个速度很快,可以忽略不记。

然后再把图片用 img:split()分割图片,image.corp()把图片裁剪的尽可能小
为什么要剪小呢?大家想一下,出现干扰点最多的地方并不是字符的部位,反而是周围空白的部位。
这样尽可能不要周围的空白,就可以去除大量的干扰点

然后使用 img:median(2) 进行中值滤波,这是降噪的作用,即去除杂点
使用 img:median()以后图片可能被破坏一点,这个没有关系,只要能保留大半特征即可。

经过以上的处理,杂点基本已经不存在。
最后,我们使用LAScript中的 imgX:testXX() 函数识别验证码。
(这种验证码用 imgX:testX() 或 imgX:test() 识别效果就不好了 )

一、下载验证码样本

打开c:\test文件夹,选“查看缩略图”,
然后重复运行下面的LAScript脚本(每次更换验证码的网址,可以通过刷新贴吧得到不同的验证码网址,右键点验证码,然后点属性就可以看到网址了),

每运行一次,就查看c:\test下自动生成的图片,把图片上的字符改为文件名.
例如图片上面显示5,就把文件名改为5.jpg

img = image.new();
--下载图像,没有后缀名要显示指定*.bmp格式
img:getURL("http://post-js.baidu.com/cgi-bin/c?1381747384&876744693","*.jpg")
--附注:image库也有抓屏函数,可以直接在屏幕上截取验证码。
image.corp(img, 9 ,0 , 41 , 20 )
img:save("c:\\test\\test.jpg") --保存到硬盘

--折分图片,指定一行四列
img2,img3,img4,img5 = img:split(1,4);

img2:save("c:\\test\\0001.jpg")
img3:save("c:\\test\\0002.jpg")
img4:save("c:\\test\\0003.jpg")
img5:save("c:\\test\\0004.jpg")

image.del(img);

三、生成验证码样本数据库

运行下面的脚本,把所有的验证码样本保存到ApeML数据岛

codeKey ={};
--添加所有数字键
for i =0,9,1 do
codeKey[""..i] = 0; --这里我们用字符串连接的方法把数字转换为字符串
end;

--k参数为键,v参数表示值 一个典型的table迭代器回调函数
loadCodeKey = function(k,v)
local img = image.new();
img:load("C:\\test\\"..k..".jpg")

img:bpp(1);
img:bpp(24);
img:corp( 1 , 0 , 9 , 10)
img:median(2)

--img:save("C:\\test2\\"..k..".jpg")
codeKey[k]= string.encode( img:getBytes("*.jpg") , ""); --因为转换到字符串还是二进制,所以用base64进行编码
image.del(img);
end;

--遍历表codekey的所有元素,调用loadcodekey加载图片文件
table.foreach (codeKey, loadCodeKey);

--把所有图片保存到数据岛,
ape:saveTable(codeKey,"验证码样本")

复制上面的代码到"源码编辑器"内,点击"编译生成模拟程序"
然后点击"回放运行" .最后点击"读取源代码"

然后你可以在源代码最后面的"数据区块"看到生成的验证码样本了

四、识别验证码 源程序下载

全部程序下载(内附源代码,没有加密): 下载已删除

1.问题:不能识别web窗体(如贴吧群发不输入关键字)
原因:你用其他的浏览器打开了贴吧,因为同时IE窗体,标题也相同,导至WEB窗体无法识别.
解决:关闭其他浏览器

2 问题:不能识别web窗体
原因:你在其他网站下载了模拟精灵,主程序的名字不是Fairy_Ape.exe,或者你改了名字.
解决:确决源代码里的Fairy_Ape.exe与模拟精灵主程序的实际名字相符

3问题:不能正常运行模拟程序、不输入关键字
原因:因为浏览器默认字体大小与录制的时候不相符,导致网页元素移动了位置
解决:设置字体与录制的时候相同,如贴吧群发字体大小应为中号

4问题:不能正常运行、不输入关键字
原因:您使用的桌面主题与我录制的时候不一样,导致控件坐标有轻微的误差
解决:把XP桌面主题设为"windows经典"以后解决

5问题:不能打开贴吧
原因:您没有把http://post.baidu.com加入IE信任站点

一、序
大家知道,识别验证码、图文识别都是技术开发的难题,人眼能轻易分别的字符,计算机却需要大量的计算,而且结果很难做到准确。就算是用C++来做,也是很费劲很难得到好的效果。不过在这里我们使用模拟精灵,可以很简单的完成图文识别,模拟精灵虽然大小不足1M、而且是绿色软件完全独立运行,却内置了大部份常用的类库,如模拟编程、WEB编程、windows编程、图像编程都可以轻松实现

二、下载验证码样本

打开c:\test文件夹,选“查看缩略图”,然后重复运行下面的LAScript脚本(每次更换验证码的网址),下载百度贴吧的所有验证码并存为样本,例如图片一,就改名为1.jpg

img = image.new();
--下载图像,没有后缀名要显示指定*.bmp格式
img:getURL("http://post-js.baidu.com/cgi-bin/c?1381747384&876744693","*.jpg")
--附注:image库也有抓屏函数,可以直接在屏幕上截取验证码。
image.corp(img, 9 ,0 , 41 , 20 )
img:save("c:\\test\\test.jpg") --保存到硬盘

--折分图片,指定一行四列
img2,img3,img4,img5 = img:split(1,4);

img2:save("c:\\test\\0001.jpg")
img3:save("c:\\test\\0002.jpg")
img4:save("c:\\test\\0003.jpg")
img5:save("c:\\test\\0004.jpg")

image.del(img);

三、生成验证码样本数据库

运行下面的脚本,把所有的验证码样本保存到ApeML数据岛

codeKey ={};
--添加所有数字键
for i =0,9,1 do
codeKey[""..i] = 0; --这里我们用字符串连接的方法把数字转换为字符串
end;

--k参数为键,v参数表示值 一个典型的table迭代器回调函数
loadCodeKey = function(k,v)
local img = image.new();
img:load("C:\\test\\"..k..".jpg")
codeKey[k]= string.encode( img:getBytes("*.jpg") , ""); --因为转换到字符串还是二进制,所以用base64进行编码
image.del(img);
end;

--遍历表codekey的所有元素,调用loadcodekey加载图片文件
table.foreach (codeKey, loadCodeKey);

--把所有图片保存到数据岛,
ape:saveTable(codeKey,"验证码样本")

四、识别验证码

运行下面的脚本测试一下


--从数据区块读取base64编码的图片数据
codekey = ape:loadTable("验证码样本");
imgBinKey = {}; --这是一个图像数组,用来储存还原后的验证码样本的图片数据
--必须进行一个转换,因为codekey里面只是base64编码的普通字符串,而imgBinKey 将是真正的图片对象(二进制数据)

--还原到图片对象
toImage = function(k,v)
local img9 = image.new();
img9:setBytes( string.decode( v ,"") ,"*.jpg");
imgBinKey[k] = img9;
end;

table.foreach(codekey,toImage);

--下载验证码图片
imgD = image.new();
if (imgD:getURL("http://post-js.baidu.com/cgi-bin/c?1281496520&1833052661","*.jpg") ~= true) then
win.messageBox("下载图像失败","")
image.del(imgD)
do return false end;
end;

image.corp(imgD, 9 ,0 , 41 , 20 );
--使用split函数分割图片
img2,img3,img4,img5 = imgD:split(1,4);

function test(imgX)
limit = 1;
chr = "";
win.messagePrint("正在检测图片,请稍候....")
testimg = function(k,v)
local n = imgX:testX(imgBinKey[k]);
if(n<limit)then
limit = n;
chr = k.."";
end;
end;
table.foreach(imgBinKey,testimg);
return chr;
end;

win.messageBox("验证码".. test(img2)..test(img3)..test(img4)..test(img5),"")

posted on 2007-08-22 17:35  Thunderdanky  阅读(2511)  评论(2编辑  收藏  举报