这篇文章上次修改于 3386 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

    最近闲来无事,研究了一下python破解验证码

    参考地址:http://vipscu.blog.163.com/blog/static/18180837220134234528457/

    具体思路如下:

       1、采样,采集目标网站的验证码样本

       2、将采集的样本验证码进行二进值转化,也即是背景变白,验证码文字变黑

       3、分割转化好的验证码,挑选好的作为模

       4、将要破解的验证码与库里面的模对比

    直接上代码:

      1、采样,采集目标网站的验证码样本

#encoding:utf-8
import urllib
#验证码地址
url="http://www.njjg.gov.cn:81/GetValidate.aspx"
for i in range(50):
    print "download", i
    file("./code/%04d.jpg" % i, "wb").write(urllib.urlopen(url).read())

     

      2、二进值转化

#encoding:utf-8
#二值化处理下载的图片
import os
from PIL import Image
j=1
dir='./code/'
path='./font/'
for f in os.listdir(dir):
    if f.endswith('.jpg'):
        img=Image.open(dir+f) #读取图片     
        img=img.convert('RGBA')
        pixdata = img.load()
        #二值化处理 即验证码变成黑色,背景变成白色
        for y in xrange(img.size[1]): #img.size[1] 图片高度
            for x in xrange(img.size[0]): #img.size[0] 图片宽度
                if pixdata[x,y][0] == 192:
                    pixdata[x,y]=(255,255,255,255)      
        for y in xrange(img.size[1]): #img.size[1]图片高度
            for x in xrange(img.size[0]): #img.size[0]图片宽度
                if pixdata[x,y][0] < 90:
                    pixdata[x,y]=(0,0,0,255)
        for y in xrange(img.size[1]): #img.size[1] 图片高度
            for x in xrange(img.size[0]): #img.size[0] 图片宽度
                if pixdata[x,y][1] < 255:
                    pixdata[x,y]=(0,0,0,255)
        img.save(path+f,"jpeg")

 

      3、制作库模

import os,Image
j=1
dir='./font/'
for f in os.listdir(dir):
    if f.endswith(".jpg"):
        img=Image.open(dir+f)
        for i in range(4):
            x=3+i*18 #这里的3和18是根据具体的验证码算出来的
            y=4 #4是根据具体的验证码算出来的 可以用ps打开,放大图片来数出像素
            img.crop((x,y,x+13,y+14)).save("./font/mode/%d.jpg" % j)
            print "j=",j
            j += 1

 

    4、准备工作做完,编写主程序代码

#encoding:utf-8
import os
from PIL import Image
#转化二进值
def binary(f):
    img = Image.open(f)
    img = img.convert('RGBA')
    pixdata = img.load()
    for y in xrange(img.size[1]): #img.size[1] 图片高度
        for x in xrange(img.size[0]): #img.size[0] 图片宽度
            if pixdata[x,y][0] == 192:
                pixdata[x,y]=(255,255,255,255)      
    for y in xrange(img.size[1]): #img.size[1]图片高度
        for x in xrange(img.size[0]): #img.size[0]图片宽度
            if pixdata[x,y][0] < 90:
                pixdata[x,y]=(0,0,0,255)
    for y in xrange(img.size[1]): #img.size[1] 图片高度
        for x in xrange(img.size[0]): #img.size[0] 图片宽度
            if pixdata[x,y][1] < 255:
                pixdata[x,y]=(0,0,0,255)
    return img
#图形分割
nume = 0
def division(img):
    global nume
    font=[]
    for i in range(4):
        x=3+i*18
        y=4
        temp=img.crop((x,y,x+13,y+14))
        temp.save("./tmp/%d.jpg" % nume)
        nume=nume+1
        font.append(temp)
    return font
#取出对应的值 
def recognize(img):
    fontMods = []
    modelist = [1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
    for i in modelist:
        file="./mode/%s.jpg" % i
        if os.path.isfile(file):
            fontMods.append((str(i), Image.open("./mode/%s.jpg" % i)))
    result=""
    font=division(img)
    for i in font:
        target=i
        points = []
        for mod in fontMods:
            diffs = 0
            for yi in range(14):
                for xi in range(13):
                    if 0 in target.getpixel((xi,yi)):
                        compare=0
                    else:
                        compare=255
                    if 0 in mod[1].getpixel((xi, yi)):
                        tcv=0
                    else:
                        tcv=255
                    if tcv != compare:
                        diffs += 1
            points.append((diffs,mod[0]))
        points.sort()
        print points
        result += points[0][1]
    return result   
if __name__ == '__main__':    
    imgfile="./code/0041.jpg"
    img=binary(imgfile)
    rs=recognize(img)
    print rs

 

小结:

    次方法的关键在于制作库模,库模做的准确则破解成功率就高