验证码识别

本文所使用的验证码识别的方法非常暴力,高手可忽略。对于在客户端实现的“伪验证码”或使用静态图片的验证码,本文不作讨论。对于验证码的识别,一直以为,只要足够的样本,就可以分析出验证码的特征,从而进行分门别类,再通过和样本做比较,就可以得出正确验证码。这里简单而暴力的验证一下这个一直想验证而没有行动过的想法。做实验的网站是某体检机构,因为它生成的验证码很有规律(不确定是不是静态文件,但就可以当成是算法随机生成的),每个字符的位置相对固定,虽然每个字符的颜色和背景都不一样,但是背景颜色很相近,没有干扰线,更重要的是,它和中国很多很多网站的验证码很类似。相关代码和文件(某体检机构网站忽略):verification code identified。 暴力步骤:

  1. 下载样本数据。
    任何有验证码的网络,都有刷新按钮,一般而言点击该按钮,就会向服务器发送一个HTTP GET的请求,我们可以根据这个请求下载大量的样本数据。一般可以通过查看HTML源码可以看到这个请求的URL和相关信息,也可以用wireshark抓下包,很容易就可以得到请求的信息。由于要用肉眼分析每个样本数据,所以,为了不增加肉眼的负担,分析的数据只下载了200个。当然是用脚本下载的,对应的代码为:sample.py。样本数据如图:
    样本数据
  2. 分析样本
    每个验证码颜色都有可能不一样,但是背景都是和验证码的数据的颜色有明显的不同,而且背景的颜色相差不大。于是,为了方便处理,我们可以将背景颜色都变成白色,验证码变成黑色。如何识别背景的颜色?仔细观察下,初步用个非常简陋的方法:首先,取4个角落的,9个像素,如果其他位置的颜色和这36个角落的颜色相差在一定的范围内,我们认为都是背景,变成白色。其他非白色的区域,都是黑色(后来,证实,这个方法不好,因为有些验证码在边边角角里)。然后,因为各个验证码的位置都相对固定(相对而已,有一些是重叠的),将各个验证码切成一个数字字符的。对应的代码:analyse.py。处理的结果:
    样本处理结果

    这里处理处理的样本数据有4X200,800个,如果用作标准样本,识别正确率会高很多,但是,笔记本计算机资源有限,从中挑出有代表性的26+25+10,61个(因为我实在区分不出大小的I和小写的l有什么区别,所以没有大写的I了)。由于PIL处理保存图片时,为了使图片更自然,会加上反锯齿,所以看到的图片不是全黑白的,还有一点灰阶,这样会降低识别的正确率,由于PIL不熟悉,不知道哪里设置,作罢。
    有效标准样本
  3. 验证码识别
    有了样本数据,就可以用样本来做对比了。同样,是按照分析样本的方法,将待测试的数据切分为几个部分,分别和样本的数据一个一个的对比,如果颜色差别在允许的范围内就认为相等,相似度最高的,就认为和样本一致,就可以认为是该样本的值。再次下载500多个验证码来测试,对应代码:crack.py。识别结果:
    测试结果
  4. 结果分析
    测试的验证码540个左右,识别错误约70个(粗略统计,眼累),识别正确率大约86%。仔细观察识别错误的验证码大多是:l -> i k -> i r -> i, l->i和r->i容易识别错误,这个可以理解,但是k->i,就迷惑了。 相关错误结果:
    错误结果

85%左右的正确率,暴力破解其实也可以了,改进下有可能达到90%以上。验证码是网络的一道屏障,破解了验证码后,很多邪恶的事情都可以做。当然这里介绍的是最笨的方法,对于复杂的验证码还不能识别,还需要更复杂点的方法。本文仅是图片识别技术的讨论,相关的代码等仅用于学习,不得用于做非法事情。