python研究之python验证码的自动识别

20160603: 文中涉及到的文件,下载地址已更新。

 

整爬虫轮子时总会遇到需要输入验证码的尴尬时刻,而python自动识别验证码的功能和模块还是比较少并且识别能力也是有限的。如果遇到逆天的验证码——12306让你识别拖把狗和拖把——那就跪安吧。本文就讲解两种验证码的识别,验证码本身有比较强的风格,可以指定使用那一类的风格。
 

 

环境介绍

这里提到的修改版的pytesser模块省略了tesserORC的安装,直接内置了tesser

验证码识别

我们首先使用验证码辅助工具(次世代验证码识别系统)来验证想法,如果达到目的就可以着手代码实现了。

字符同色处理

看下面这个验证码:
type1

从图中可以看出来,虽然每一个字母的颜色都跟其他字母的颜色不一致,但是单个字母内部的颜色都基本一致,这时候我们可以考虑使用亮度筛选。
来验证一下,首先分离亮度(经验上这类图片直接二值化处理效果不佳):
fenliliangdu
可以看出来,完美的将字符提取出来了。那么开始代码实现

def rgb(im):
    '''获取每一个像素的亮度     (r+g+b)/3
    '''
    width, heigth = im.size
    data = np.zeros((heigth,width))
    aa = []
    for w in range(width):
        for h in range(heigth):
            
            y,cb,cr=im.getpixel((w,h)) 
            data[h,w] = (y+cb+cr)/3
            aa.append((y+cb+cr)/3)
    data = pd.DataFrame(data)
    aa = pd.Series(aa)
    return aa,data


上面代码的功能是将图片中每个像素的亮度计算出来并以列表和矩阵的形式分别返回。
在矩阵中就基本可以看到字母了,比如里面的字母A:
字母A,注意看数字为88的区域

 

def topliangdu(liangdu, biaozhun=100):
    '''根据亮度排序,取大于标准的值
    '''
    c=liangdu.value_counts()
    return list(c[c>100].index)

实际上,亮度提取就是提取重复度很高的几个颜色,只要将非这个颜色的像素填充白色就可以实现去背景功能。

def liangdutianbai(im,mubiao):
    '''将非目标区域填充白色'''
    width, heigth = im.size
    for w in range(width):
        for h in range(heigth):
            y,cb,cr=im.getpixel((w,h)) #提取点(10,10)位置的亮度、蓝色分量、红色分量的值。
            tmp = (y+cb+cr)/3
            if tmp not in mubiao:
                im.putpixel([w,h],(255, 255, 255))
    return im


封装上述函数并且二值化去色:
 

def tongse(im):
    '''验证码验证文字的单个文字同色时,处理。'''
    global aa, data
    aa,data = rgb(im)
    mubiao = topliangdu(aa)
    im = liangdutianbai(im, mubiao)
    img_grey = im.convert('L')
    img_grey.show()
    return img_grey

最终测试:
 

im = Image.open('type1.png')
text = image_to_string(tongse(im))  # 将图片转成字符串
print text

直接二值化处理

这一类图片
type2
对很多验证码,首先尝试二值化处理,如果失败再考虑其他方法。

def erzhihua(im, point=127):
    '''图片二值化处理'''
    img_grey = im.convert('L')
    threshold = point
    table = []
    for i in range(256):
        if i < threshold:
            table.append(0)
        else:
            table.append(1)
    img_out = img_grey.point(table, '1')
    img_out.show()
    img_out.save('tmp.bmp')

    return img_out


最终测试:

im = Image.open('type2.jpg')
text = image_to_string(erzhihua(im))  # 将图片转成字符串
print text


 

评论 (4)
  1. 沙发
    ocr 2016-05-18 11:47

    额,下载链接失效了。然后请问- 修改版的pytesser模块(PY2.7)。修改版的pytesser模块省略了tesserORC的安装,直接内置了tesser。这俩可以发出来么.包括破解版的次世代

    • 回复
      kingmo888 2016-05-19 23:08
      @ocr 你好,好久没登录后台,刚看到评论。 这是我从hexo程序转为wp博客前的文章,地址可能发生了变化,你所要求的东西都可以放出来,明天更新一下。
  2. 板凳
    习惯 2017-07-20 06:02

    Traceback (most recent call last):
    File “E:/Pycharm_py/selenium_py/identifying_code.py”, line 71, in
    text = pytesseract.image_to_string(tongse(qq)) # 将图片转成字符串
    File “E:/Pycharm_py/selenium_py/identifying_code.py”, line 61, in tongse
    aa,data = rgb(im)
    File “E:/Pycharm_py/selenium_py/identifying_code.py”, line 29, in rgb
    data = np.zeros((heigth,width))
    NameError: global name ‘np’ is not defined

  3. 地板
    csyzbb 2017-09-05 09:13

    不知道是哪里出了问题,可能是没有使用楼主的pytesser,使用的原生+ORC 怎么尝试都提示Empty page!!
    使用楼主自己的验证码也是