广告
返回顶部
首页 > 资讯 > 后端开发 > Python >实验楼Python破解验证码
  • 610
分享到

实验楼Python破解验证码

验证码实验楼Python 2023-01-30 22:01:07 610人浏览 独家记忆

Python 官方文档:入门教程 => 点击学习

摘要

  本人大二,因为python结业考试项目,又想要学习机器学习方向,但是由于接触时间不长,选择了实验楼的Python破解验证码这个项目作为我的项目, 我在原来的基础上加了一些代码用于完善,并且对功能如何实现记录在此,第一次接触到图像识别的

  本人大二,因为python结业考试项目,又想要学习机器学习方向,但是由于接触时间不长,选择了实验楼的Python破解验证码这个项目作为我的项目,

我在原来的基础上加了一些代码用于完善,并且对功能如何实现记录在此,第一次接触到图像识别的项目。

  这是项目需要的文件链接:https://pan.baidu.com/s/1qoJ5qvU9idmH0v7dnFkMCw  

  总体思想是将验证码变成黑白,然后切割成单字符,再与准备好的训练集相互比对,将相似度最高的字符输出。

  第一步,先对一个验证码进行处理,,①目标是将图片尽量简化成黑白,②然后切割出单字符,对此使用的是PIL的Image库。

  ①导入图片,转换成8位像素的图片

#加载图片并且转换成8位像素
im = Image.open("./captcha.gif")
im.convert("P")

  我们需要知道验证码的颜色,拾色器工具是一种方法,但是我们通过数据说话,通过打印直方图 print(im.histogram()) 可以返回如下列表

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 1, 2, 0, 1, 0, 0, 1, 0, 2, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 3, 1, 3, 3, 0, 0, 0, 0, 0, 0, 1, 0, 3, 2, 132, 1, 1, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 15, 0, 1, 0, 1, 0, 0, 8, 1, 0, 0, 0, 0, 1, 6, 0, 2, 0, 0, 0, 0, 18, 1, 1, 1, 1, 1, 2, 365, 115, 0, 1, 0, 0, 0, 135, 186, 0, 0, 1, 0, 0, 0, 116, 3, 0, 0, 0, 0, 0, 21, 1, 1, 0, 0, 0, 2, 10, 2, 0, 0, 0, 0, 2, 10, 0, 0, 0, 0, 1, 0, 625]

  列表每一个元素代表在图片中含有对应位的颜色的像素的数量。(白色255,黑色是0)

  接下来进行排序

his = im.histogram()
values = {}
#将颜色作为键,出现次数作为值,形成字典
for i in range(256):
    values[i] = his[i]
#对字典进行排序,排序根据字典的值(x[0]是字典的键),从大到小排序
for j,k in sorted(values.items(),key=lambda x:x[1],reverse = True)[:10]:
    print(j,k)

  即可得到以下

255 625
212 365
220 186
219 135
169 132
227 116
213 115
234 21
205 18
184 15

  220与227是我们所需要的红色,于是我们可以创建一个相同大小的纯白色的图片,将符合的颜色变为黑色0

 (其实这里也就表现了这个程序的第一个局限性,颜色要人为判断,并且每一个字符都要颜色统一)

# 构造一个纯白的等大小的图片im2
im2 = Image.new("P", im.size, 255)
#遍历加载的图片,对每个像素点判断是否符合要求
for x in range(im.size[1]):         #im.size[1]是垂直像素数
    for y in range(im.size[0]):     #im.size[0]是水平像素数
        pix = im.getpixel((y, x))       #获取每一个像素点的颜色纸
        if pix == 220 or pix == 227:    #判断是否符合220或者227
            im2.putpixel((y, x), 0)     #符合则变成黑色

  之后用im2.show(),可以看到这个很符合我们的想法

  ②然后我们需要切割出单个字符,实验楼里面说:“由于例子比较简单,我们对其进行纵向切割:”,恕我刚刚接触时间不长,还不太能了解这句话后面的深度

  具体做法就是纵向从左到右“一刀刀往下切”

  一个变量判断是否切到了黑色的像素点,切到则转换“刀”为切到字符的状态并且记录当前的水平位置,

如果没有切到黑色像素点,但是“刀”依旧是切到字符的状态,则重置“刀”为未切到字符的状态并且当前的记录水平位置,

第一次记录的位置到第二次记录的位置一定有一个字符。

inletter = False  #判断是否切割到了字符
foundletter = False     #未切到字符的状态记录
start = 0       #记录开始的x值
end = 0          #记录结束的x值
letters = []    #记录切割到的字符
#纵向切割记录数据
for x in range(im2.size[0]):    #遍历水平的像素点
    for y in range(im2.size[1]): #同一水平值下遍历垂直的(用刀切)
        pix = im2.getpixel((x, y))  #获取像素点颜色
        if pix != 255:           #碰到黑色就位切到了
            inletter = True
    # 切到但是刀的状态是没有切到,则转换刀的状态为切到
    if foundletter == False and inletter == True:
        foundletter = True
        start = x

    #如果上面if没有成立,则下面的if不会发生,所以letters一定会记录到2个不同的值

    #没有切到但是刀的状态是切到了,则转换刀的状态为未切到
    if foundletter == True and inletter == False:
        foundletter = False
        end = x
        letters.append((start, end))
    #重置为未切到字符
    inletter = False

  打印letters,符合预期

[(6, 14), (15, 25), (27, 35), (37, 46), (48, 56), (57, 67)]

 然后将记录到的数据,对图片进行切割

#切割字符
for letter in letters:
    #参数一个四元组,四个元素依次是左上角的x和y值与右下角的x和y值
    im3 = im2.crop((letter[0], 0, letter[1], im.size[1]))

  然后可以遍历保存im3为.gif格式,可以得到6个图片                    都是单独的字符了,至此第一步完成

  接下来就是核心的第二步,怎么把每一个字符输出对应的数字?

  首先是实验楼给出的论文网站Http://ondoc.logand.com/d/2697/pdf

  “也说了这个这个方法的优缺点:

  • 不需要大量的训练迭代
  • 不会训练过度
  • 你可以随时加入/移除错误的数据查看效果
  • 很容易理解和编写成代码
  • 提供分级结果,你可以查看最接近的多个匹配
  • 对于无法识别的东西只要加入到搜索引擎中,马上就能识别了。

  当然它也有缺点,例如分类的速度比神经网络慢很多,它不能找到自己的方法解决问题等等。”

  然后实验楼只是简单的介绍了一下原理,并未详细说明,为此我通读了整篇论文,来说说我的一点理解。

  有1篇讲猫和狗和鼠的文章,但是我想知道这篇文章主要讲的是哪个动物,为此我将“猫”,“狗”,“鼠”这几个特征性的单词作为我的重点关注对象,并建立一个一个三维空间,x轴对应“猫”这个单词出现的次数,同理y轴对应“狗”,z轴对应“鼠”。首先先用于第一篇文章,“猫”出现一次,x就加1,“狗”出现一次,y就加1,“鼠”出现一次,z就加1,那么整篇文章遍历完了,就一定在三维空间中有一个向量(x1,y1,z1)对应出现次数,然后将这个向量投影在x,y,z轴的值,最大的值对应的轴就是这篇文章出现最多的单词了,也应该是这篇文章主要讲的动物了。

  在x轴上的投影为在向量大小为定值时,夹角越小,余弦越大,则投影越大,所以我们不用计算出具体的投影的值,问题转化成了求夹角的余弦即可。

  两向量的夹角公式带入相应的数值即可得到即可知道和x轴夹角,同理与y轴夹角与z轴夹角之后只需要找出最大的余弦值,对应的字符就是最相关的。

  这是基本矢量空间搜索引擎理论的含义,然后将这个方法用于图片,会变得更加的复杂,但是核心思想并未改变。

  然后我们照着改一下。

  有1个未知字符(字母或者数字)的图片,但是我想知道这个字符讲的是哪个字符,为此我找了26+10个对应不同字符的图片作为我的已知的标准,将标准图片的每个像素点的颜色作为我的重点关注对象,再并建立一个n维向量,每一维则对应一个标准图片的像素点位置,我只要把未知图片每一个像素点的颜色值值代入,以及标准图片每一个像素点的颜色值代入,最后一定有2个向量表示未知图片和这一个标准图片,然后求未知图片与这一标准图片的向量的夹角的余弦值,然后用同样方法做36遍,再按照相似度从大到小排序即可,最大余弦值的对应的已知字符应该最接近。这有个要求就是我们的标准的像素点的数量和未知的图片像素点数量要想接近,这应该涉及到了数据预处理的问题,我还没有学,但是我觉得如果像素点数量差距变大,会很影响判断的,所以以下,我们当我们的数据都很好的预处理了。

  总的来说,和原本的区别就是我们的重点关注对象变多了,以及我们的标准也不只是单单的坐标轴了,标准也变成一个向量。综上我们一共需要完成①图片变成矢量②计算矢量大小③计算夹角

  ①图片准换成矢量,我们定义成为一个函数,返回一个字典,键就是像素点位置(0,1,2,3...),值就是像素点颜色(0,255)

#图片转换成矢量,字典化图片
def buildvector(im):#参数是字符的图片
    d1 = {}         #字典记录像素点位置和对应的颜色
    count =0        #用来增加像素点位置
    for i  in im.getdata(): #i就是从0开始对应的颜色值
        d1[count] = i   #把颜色值作为值加入字典
        count +=1       
    return d1       #返回{像素点位置:颜色}的字典

  ②计算矢量大小以及③计算夹角同时放在一个类里面

import math
#比较矢量相似度的类 class VectorCompare: #计算矢量大小,即求余弦的分母的元素 def magnitude (self,concordance): total = 0 for Word,count in concordance.items():#word像素点位置,count对应的颜色(0或255) total += count**2 return math.sqrt(total) #求出向量的模的大小 #计算矢量的夹角 def relation(self,concordance1,concordance2): #输入两个字典化图片 topvalue =0 #求余弦公式的分子 for word,count in concordance1.items(): #需要很好的数据预处理 if word in concordance2: # 每一维度(像素点),两向量的颜色值(0或255)相乘,求出余弦公式分子 topvalue += count *concordance2[word] all_magnitude = self.magnitude(concordance1)*self.magnitude(concordance2) #求余弦公式的分母 relevance = topvalue/all_magnitude #求出余弦 return relevance #返回相关性

  之后就是要用图片转换矢量函数先把我的标准训练集先完成,而标准训练集就是iconset文件夹下的文件,我们需要从iconset文件夹里把每一个图片和文件夹的名字一一对应上,所以我们需要用os库来获取文件名

#训练集名字
iconset = ['0','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']

#加载训练集
imageset = []   #[{正确名字1:[字典化图片]}, {正确名字2:[字典化图片]}, {正确名字3:[字典化图片]}。。。]
#字典化iconset里面图片
for letter in iconset:  #遍历iconset所有要训练的名字
    for img in os.listdir("./iconset/%s"%(letter)): #遍历所有iconset里面的文件夹
        temp = []       #列表用来记录字典化图片
        if img != "Thumbs.db" and img!= ".DS_Store":    #不需要训练的文件
            temp.append(buildvector(Image.open("./iconset/%s/%s"%(letter,img))))  #生成字典化图片
        imageset.append({letter:temp})  #将训练的名字和字典化图片再对应

  最后一步,把我们之前切的im3逐一遍历,再排序出相似度最高的对应的正确名字,最后打印出所有字符串

#判断单个字符的相似度
str = ""          #打印字符串
for letter in letters:
    im3 = im2.crop((letter[0], 0, letter[1], im.size[1]))
    guess = []  #记录和所有训练集的数据,用来排序
    for image in imageset:  #和所有训练集的数据进行遍历
        for x, y in image.items():  #x是正确名字,y是对应的[字典化图片]
            if len(y) != 0: #y不为空,除去是Thumbs.db和.DS_Store训练出来的空列表
                guess.append((v.relation(y[0], buildvector(im3)), x))#y[0]就是字典化图片
    guess.sort(reverse=True) #从大到小排序
    str += "{}".fORMat(guess[0][1]) #相似度最高的字符加到字符串里
print(str)  #打印

  打印结果为

7s9t9j

  这一个到此为止成功。实验楼的项目至此结束

  所有代码

from PIL import Image
import math
import os

#比较矢量相似度的类
class VectorCompare:
    #计算矢量大小,即求余弦的分母的元素
    def magnitude (self,concordance):
        total = 0
        for word,count in concordance.items():#word像素点位置,count对应的颜色(0或255)
            total += count**2
        return math.sqrt(total)         #求出向量的模的大小

    #计算矢量的夹角
    def relation(self,concordance1,concordance2):   #输入两个字典化图片
        topvalue =0                                #求余弦公式的分子
        for word,count in concordance1.items():     #需要很好的数据预处理
            if word in concordance2:
                # 同一维度(像素点),两向量的颜色值(0或255)相乘,求出余弦公式分子
                topvalue += count *concordance2[word]
        all_magnitude = self.magnitude(concordance1)*self.magnitude(concordance2)   #求余弦公式的分母
        relevance = topvalue/all_magnitude      #求出余弦
        return relevance            #返回相关性

#图片转换成矢量,字典化图片
def buildvector(im):#参数是字符的图片
    d1 = {}         #字典记录像素点位置和对应的颜色
    count =0        #用来增加像素点位置
    for i  in im.getdata(): #i就是从0开始对应的颜色值
        d1[count] = i   #把颜色值作为值加入字典
        count +=1
    return d1       #返回{像素点位置:颜色}的字典

#实例化
v = VectorCompare()
#训练集名字
iconset = ['0','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']

#加载训练集
imageset = []   #[{正确名字1:[字典化图片]}, {正确名字2:[字典化图片]}, {正确名字3:[字典化图片]}。。。]
#字典化iconset里面图片
for letter in iconset:  #遍历iconset所有要训练的名字
    for img in os.listdir("./iconset/%s"%(letter)): #遍历所有iconset里面的文件夹
        temp = []       #列表用来记录字典化图片
        if img != "Thumbs.db" and img!= ".DS_Store":    #不需要训练的文件
            temp.append(buildvector(Image.open("./iconset/%s/%s"%(letter,img))))  #生成字典化图片
        imageset.append({letter:temp})  #将训练的名字和字典化图片再对应


# 加载图片并且转换成8位像素
im = Image.open("./captcha.gif")
im.convert("P")
# 构造一个纯白的等大小的图片im2
im2 = Image.new("P", im.size, 255)
# 遍历加载的图片,对每个像素点判断是否符合要求
for x in range(im.size[1]):  # im.size[1]是垂直像素数
    for y in range(im.size[0]):  # im.size[0]是水平像素数
        pix = im.getpixel((y, x))  # 获取每一个像素点的颜色纸
        if pix == 220 or pix == 227:  # 判断是否符合220或者227
            im2.putpixel((y, x), 0)  # 符合则变成黑色

inletter = False  # 判断是否切割到了字符
foundletter = False  # 未切到字符的状态记录
start = 0  # 记录开始的x值
end = 0  # 记录结束的x值
letters = []  # 记录切割到的字符
# 纵向切割记录数据
for x in range(im2.size[0]):  # 遍历水平的像素点
    for y in range(im2.size[1]):  # 同一水平值下遍历垂直的(用刀切)
        pix = im2.getpixel((x, y))  # 获取像素点颜色
        if pix != 255:  # 碰到黑色就位切到了
            inletter = True
    # 切到但是刀的状态是没有切到,则转换刀的状态为切到
    if foundletter == False and inletter == True:
        foundletter = True
        start = x

    # 如果上面if没有成立,则下面的if不会发生,所以letters一定会记录到2个不同的值

    # 没有切到但是刀的状态是切到了,则转换刀的状态为未切到
    if foundletter == True and inletter == False:
        foundletter = False
        end = x
        letters.append((start, end))
    # 重置为未切到字符
    inletter = False

# 判断单个字符的相似度
str = ""  # 打印字符串
for letter in letters:
    im3 = im2.crop((letter[0], 0, letter[1], im.size[1]))
    guess = []  # 记录和所有训练集的数据,用来排序
    for image in imageset:  # 和所有训练集的数据进行遍历
        for x, y in image.items():  # x是正确名字,y是对应的[字典化图片]
            if len(y) != 0:  # y不为空,除去是Thumbs.db和.DS_Store训练出来的空列表
                guess.append((v.relation(y[0], buildvector(im3)), x))  # y[0]就是字典化图片
    guess.sort(reverse=True)  # 从大到小排序
    str += "{}".format(guess[0][1])  # 相似度最高的字符加到字符串里

  

  之后便要对所有的examples文件夹下的验证码都进行训练,看看准确度如何

  从加载图片到最后的判断字符都放入一个for循环语句当中

for listname in os.listdir("./examples"):

  以及验证码图片的加载也要修改为

    if listname != "Thumbs.db" and listname != ".DS_Store":
        im = Image.open("./examples/%s" % (listname))
        im.convert("P")

  下面的所有代码都要这个if条件下才能实施,全部再缩进一行

  当我再次打印输出的时候显示的验证码结果是

0q1dp0
0q3tje
24alb0p
47j17b
4wwfa
5dwvo
5t0qh
75rc1qp
7s9t9j
bibfkf
bf5te
9f2luc
9tmxf
9to1tkp
akfvav
aro2hz
b17lzh
b3rk8h
b3ufl9
pbmk5jx
2mybt
cw0qy
cfyrg
eb0qy3
etg5z
fnt5x
phd0qli
ivusjv
jfte2
zttiq
k0qg4l
k6e2ir
w0qlk
w7k5z
l9felg
lz73a7
t1sge
n67dmb
nlrzo7
tmisv
f15jnd
fmiunq
qfwix9
r2lvkd
r6r12e
718ft
t6khw
ibrjc
puc1rdk
v63gde
7f54eg
xfnrsn

  有长有短,但是验证码的长度应当是6个字符,对错我也并不知晓,所以我开始着手准备

我在循环前加了一系列变量用来记录我所疑惑的

success =0            #记录正确匹配个数
fail = 0                #记录失败的个数
success_name_list=[]        #记录正确匹配的名字
fail_name_list =[]          #记录失败的名字
wrong_length_name = []        #记录失败的错误长度的名字
wrong_letter_count_dict= {}       #记录失败的对应的字母错误并累加记录次数
correct_name_list = []          #记录错误所对应的正确名字,列表下标对应,对比容易

  然后我在每一次循环刚开始的时候都记录下当前验证码的正确名字,也就是图片名

correct_name = listname[:6]  # 记录正确的文件名 ,用来判断是否正确

  然后就是对结果str进行判断,并记录相关数据

        if str == correct_name: #正确
            success += 1        #正确次数加1
            success_name_list.append(str)   #记录正确的名字
        else:
            fail +=1    #错误次数加1
            fail_name_list.append(str)  #记录错误名字
            correct_name_list.append(correct_name)  #同时记录对应的正确名字用来进一步分析

  最后就是将相关数据汇总分析,我尽我能力全分析了,过程具体注释也就不详细写了,

count =0 #错误名字列表和对应的正确名字的下标一一对应
#统计出错误的原因
for letters in fail_name_list:
    # 长度不统一
    if len(letters) != len(correct_name_list[count]):
        wrong_length_name.append(letters)
        count+=1

    #长度统一,但是识别错误
    else:
        index =0
        for letter in letters:
            if letter != correct_name_list[count][index]:
                wrong_letter_count_dict[letter] = wrong_letter_count_dict.get(letter,0)+1
                index+=1
            else:
                index+=1
        count+=1


success_rate = success/(success+fail)       #成功率
#打印总数,成功和失败的数量,以及成功率
print("total count = {}\n"
      "success = {}, failed = {} \n"
       " success_rate = {}\n".format(success+fail,success,fail,success_rate))

#打印成功的验证码的名字
print("Success Trainning name:")
for i in range(len(success_name_list)):
    print(success_name_list[i])


wrong_length_count = len(wrong_length_name)                 #去除长度识别错误的数量
success_rate = success/(success+fail-wrong_length_count)    #去除长度错误的图片后的成功率
#打印错误长度的验证码的数量
print("\nWrong Length count:{}".format(wrong_length_count))
print("total count without wrong length= {}\n"
      "success = {}, failed = without wrong length = {} \n"
       "success_rate without wrong length= {:.4f}\n".format(success+fail-wrong_length_count,
                                                         success,
                                                         fail-wrong_length_count,
                                                         success_rate))

#将字母识别错误>1的输出,用来表示标准样本的错误
wrong_letter_count_list = sorted(wrong_letter_count_dict.items(),
                                 key = lambda x:x[1],
                                 reverse =True)
for letter in wrong_letter_count_list:
    if letter[1] >1:
        print("Need more {} to train".format(letter[0]))

  最后运行一下

total count = 52
success = 13, failed = 39 
 success_rate = 0.25

Success Trainning name:
0q3tje
47j17b
7s9t9j
9f2luc
b3rk8h
b3ufl9
k6e2ir
nlrzo7
qfwix9
r2lvkd
r6r12e
v63gde
xfnrsn

Wrong Length count:25
total count without wrong length= 27
success = 13, failed = without wrong length = 14 
success_rate without wrong length= 0.4815

Need more f to train
Need more b to train
Need more v to train
Need more 7 to train

  其他的数据不多说,我后来打印了错误字符的字典,发现“f”错了4次我很好奇为什么,然后打开训练集一看

好嘛,根本没有小写“f”的训练集,网上的训练集也不靠谱啊

  最后总体说说我有可能需要改进的地方,首先是之前说到的颜色,要我手动输入,而且还必须统一颜色,弄得不好还可能要多出一个字符,可是如果要解决这个要k邻近?或者涉及到神经网络了,我才刚看了一点书。。。路漫漫其修远兮。其次,根据上面的数据可以看到很多辨别失败的是因为长度辨识错误,也就是字符的像素点重合在一起了,会把两个字符合成一个字符判断,我现在想不到能用什么办法来解决这个问题。智商不够用。

  真正的最后附上我的全部代码

from PIL import Image
import math
import os


#比较矢量相似度的类
class VectorCompare:
    #计算矢量大小,即求余弦的分母的元素
    def magnitude (self,concordance):
        total = 0
        for word,count in concordance.items():#word像素点位置,count对应的颜色(0或255)
            total += count**2
        return math.sqrt(total)         #求出向量的模的大小

    #计算矢量的夹角
    def relation(self,concordance1,concordance2):   #输入两个字典化图片
        topvalue =0                                #求余弦公式的分子
        for word,count in concordance1.items():     #需要很好的数据预处理
            if word in concordance2:
                # 同一维度(像素点),两向量的颜色值(0或255)相乘,求出余弦公式分子
                topvalue += count *concordance2[word]
        all_magnitude = self.magnitude(concordance1)*self.magnitude(concordance2)   #求余弦公式的分母
        relevance = topvalue/all_magnitude      #求出余弦
        return relevance            #返回相关性

#图片转换成矢量,字典化图片
def buildvector(im):#参数是字符的图片
    d1 = {}         #字典记录像素点位置和对应的颜色
    count =0        #用来增加像素点位置
    for i  in im.getdata(): #i就是从0开始对应的颜色值
        d1[count] = i   #把颜色值作为值加入字典
        count +=1
    return d1       #返回{像素点位置:颜色}的字典

#实例化
v = VectorCompare()
#训练集名字
iconset = ['0','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']

#加载训练集
imageset = []   #[{正确名字1:[字典化图片]}, {正确名字2:[字典化图片]}, {正确名字3:[字典化图片]}。。。]
#字典化iconset里面图片
for letter in iconset:  #遍历iconset所有要训练的名字
    for img in os.listdir("./iconset/%s"%(letter)): #遍历所有iconset里面的文件夹
        temp = []       #列表用来记录字典化图片
        if img != "Thumbs.db" and img!= ".DS_Store":    #不需要训练的文件
            temp.append(buildvector(Image.open("./iconset/%s/%s"%(letter,img))))  #生成字典化图片
        imageset.append({letter:temp})  #将训练的名字和字典化图片再对应

success =0            #记录正确匹配个数
fail = 0                #记录失败的个数
success_name_list=[]        #记录正确匹配的名字
fail_name_list =[]          #记录失败的名字
wrong_length_name = []        #记录失败的错误长度的名字
wrong_letter_count_dict= {}       #记录失败的对应的字母错误并累加记录次数
correct_name_list = []          #记录错误所对应的正确名字,列表下标对应对比容易
for listname in os.listdir("./examples"):

    correct_name = listname[:6]  # 记录正确的文件名 ,用来比较
    # 加载图片并且转换成8位像素
    if listname != "Thumbs.db" and listname != ".DS_Store":
        im = Image.open("./examples/%s" % (listname))
        im.convert("P")
        # 构造一个纯白的等大小的图片im2
        im2 = Image.new("P", im.size, 255)
        # 遍历加载的图片,对每个像素点判断是否符合要求
        for x in range(im.size[1]):  # im.size[1]是垂直像素数
            for y in range(im.size[0]):  # im.size[0]是水平像素数
                pix = im.getpixel((y, x))  # 获取每一个像素点的颜色纸
                if pix == 220 or pix == 227:  # 判断是否符合220或者227
                    im2.putpixel((y, x), 0)  # 符合则变成黑色

        inletter = False  # 判断是否切割到了字符
        foundletter = False  # 未切到字符的状态记录
        start = 0  # 记录开始的x值
        end = 0  # 记录结束的x值
        letters = []  # 记录切割到的字符
        # 纵向切割记录数据
        for x in range(im2.size[0]):  # 遍历水平的像素点
            for y in range(im2.size[1]):  # 同一水平值下遍历垂直的(用刀切)
                pix = im2.getpixel((x, y))  # 获取像素点颜色
                if pix != 255:  # 碰到黑色就位切到了
                    inletter = True
            # 切到但是刀的状态是没有切到,则转换刀的状态为切到
            if foundletter == False and inletter == True:
                foundletter = True
                start = x

            # 如果上面if没有成立,则下面的if不会发生,所以letters一定会记录到2个不同的值

            # 没有切到但是刀的状态是切到了,则转换刀的状态为未切到
            if foundletter == True and inletter == False:
                foundletter = False
                end = x
                letters.append((start, end))
            # 重置为未切到字符
            inletter = False

        # 判断单个字符的相似度
        str = ""  # 打印字符串
        for letter in letters:
            im3 = im2.crop((letter[0], 0, letter[1], im.size[1]))
            guess = []  # 记录和所有训练集的数据,用来排序
            for image in imageset:  # 和所有训练集的数据进行遍历
                for x, y in image.items():  # x是正确名字,y是对应的[字典化图片]
                    if len(y) != 0:  # y不为空,除去是Thumbs.db和.DS_Store训练出来的空列表
                        guess.append((v.relation(y[0], buildvector(im3)), x))  # y[0]就是字典化图片
            guess.sort(reverse=True)  # 从大到小排序
            str += "{}".format(guess[0][1])  # 相似度最高的字符加到字符串里

        if str == correct_name: #正确
            success += 1        #正确次数加1
            success_name_list.append(str)   #记录正确的名字
        else:
            fail +=1    #错误次数加1
            fail_name_list.append(str)  #记录错误名字
            correct_name_list.append(correct_name)  #同时记录对应的正确名字用来进一步分析


count =0 #错误名字列表和对应的正确名字的下标一一对应
#统计出错误的原因
for letters in fail_name_list:
    # 长度不统一
    if len(letters) != len(correct_name_list[count]):
        wrong_length_name.append(letters)
        count+=1

    #长度统一,但是识别错误
    else:
        index =0
        for letter in letters:
            if letter != correct_name_list[count][index]:
                wrong_letter_count_dict[letter] = wrong_letter_count_dict.get(letter,0)+1
                index+=1
            else:
                index+=1
        count+=1


success_rate = success/(success+fail)       #成功率
#打印总数,成功和失败的数量,以及成功率
print("total count = {}\n"
      "success = {}, failed = {} \n"
       " success_rate = {}\n".format(success+fail,success,fail,success_rate))

#打印成功的验证码的名字
print("Success Trainning name:")
for i in range(len(success_name_list)):
    print(success_name_list[i])


wrong_length_count = len(wrong_length_name)                 #去除长度识别错误的数量
success_rate = success/(success+fail-wrong_length_count)    #去除长度错误的图片后的成功率
#打印错误长度的验证码的数量
print("\nWrong Length count:{}".format(wrong_length_count))
print("total count without wrong length= {}\n"
      "success = {}, failed = without wrong length = {} \n"
       "success_rate without wrong length= {:.4f}\n".format(success+fail-wrong_length_count,
                                                         success,
                                                         fail-wrong_length_count,
                                                         success_rate))

#将字母识别错误>1的输出,用来表示标准样本的错误
wrong_letter_count_list = sorted(wrong_letter_count_dict.items(),
                                 key = lambda x:x[1],
                                 reverse =True)
for letter in wrong_letter_count_list:
    if letter[1] >1:
        print("Need more {} to train".format(letter[0]))

 

--结束END--

本文标题: 实验楼Python破解验证码

本文链接: https://www.lsjlt.com/news/180129.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 实验楼Python破解验证码
      本人大二,因为Python结业考试项目,又想要学习机器学习方向,但是由于接触时间不长,选择了实验楼的Python破解验证码这个项目作为我的项目, 我在原来的基础上加了一些代码用于完善,并且对功能如何实现记录在此,第一次接触到图像识别的...
    99+
    2023-01-30
    验证码 实验楼 Python
  • 利用Python破解验证码实例详解
    一、前言 本实验将通过一个简单的例子来讲解破解验证码的原理,将学习和实践以下知识点: Python基本知识 PIL模块的使用 二、实例详解 安装 pillow(PIL)库: ...
    99+
    2022-06-04
    验证码 详解 实例
  • python滑块验证码如何破解
    很抱歉,我不能提供关于破解滑块验证码的信息。这是不道德且违法行为,违反了网站的服务条款和法律法规。我鼓励尊重和遵守所有的在线服务和法...
    99+
    2023-08-24
    python
  • Python破解极验滑动验证码详细步骤
    目录极验滑动验证码实现位移移动需要的基础知识对比两张图片,找出缺口获得图片按照位移移动详细代码极验滑动验证码 以上图片是最典型的要属于极验滑动认证了,极验官网:http://www...
    99+
    2022-11-12
  • 怎么用Python破解滑动验证码
    本篇文章给大家分享的是有关怎么用Python破解滑动验证码,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。相信大家在登录某些网站的时候,都会遇到请输入验证码的状态,比如在哔哔哔哔...
    99+
    2023-06-02
  • Python+selenium怎么破解拼图验证码
    这篇文章主要介绍“Python+selenium怎么破解拼图验证码”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Python+selenium怎么破解拼图验证码”文章能帮助大家解决问题。实现思路很多...
    99+
    2023-06-29
  • Python破解极验滑动验证码的示例分析
    这篇文章将为大家详细讲解有关Python破解极验滑动验证码的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。极验滑动验证码以上图片是最典型的要属于极验滑动认证了,极验官网:http://www.ge...
    99+
    2023-06-15
  • Python+selenium破解拼图验证码的脚本
    目录实现思路核心代码实现思路 很多网站都有拼图验证码 1.首先要了解拼图验证码的生成原理 2.制定破解计划,考虑其可能性和成功率。 3.编写脚本 很多网站的拼图验证码都是直接借助第三...
    99+
    2022-11-13
  • Python爬虫怎么破解滑块验证码
    这篇文章主要介绍“Python爬虫怎么破解滑块验证码”,在日常操作中,相信很多人在Python爬虫怎么破解滑块验证码问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Python爬虫怎么破解滑块验证码”的疑惑有所...
    99+
    2023-06-20
  • Python实现破解网站登录密码(带token验证)
    目录前言关键代码解释完整代码运行结果补充前言 上一篇暴力破解文章:一个简单的Python暴力破解网站登录密码脚本 测试靶机为Pikachu漏洞练习平台暴力破解模块下的 “...
    99+
    2022-11-13
  • 怎么用Python爬虫破解滑动验证码
    这篇文章给大家分享的是有关怎么用Python爬虫破解滑动验证码的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。python的数据类型有哪些python的数据类型:1. 数字类型,包括int(整型)、long(长整型...
    99+
    2023-06-14
  • selenium+java破解极验滑动验证码的示例代码
    摘要分析验证码素材图片混淆原理,并采用selenium模拟人拖动滑块过程,进而破解验证码。人工验证的过程打开威锋网注册页面移动鼠标至小滑块,一张完整的图片会出现(如下图1)点击鼠标左键,图片中间会出现一个缺块(如下图2)移动小滑块正上方图案...
    99+
    2023-05-30
  • 教你python破解滑块验证码!记得收藏!
    文章目录 前言一、滑动验证破解思路二、案例讲解三、代码实现 前言 有小伙伴们私信反馈说,在web自动化的过程中,经常会被登录的验证码给卡住,不知道如何去通过验证码的验证。今天专门给大家来...
    99+
    2023-09-04
    python 开发语言 编程 爬虫
  • python自动化测试之破解图文验证码
    对于web应用程序来讲,处于安全性考虑,在登录的时候,都会设置验证码,验证码的类型种类繁多,有图片中辨别数字字母的,有点击图片中指定的文字的,也有算术计算结果的,再复杂一点就是滑动验...
    99+
    2022-11-11
  • python自动化测试之破解滑动验证码
    在Web自动化测试的过程中,经常会被登录的验证码给卡住,不知道如何去通过验证码的验证。一般的情况下遇到验证码我们可以都可以找开发去帮忙解决,关闭验证码,或者给一个万能的验证码!那么如...
    99+
    2022-11-11
  • 用Python爬虫破解滑动验证码的案例解析
    做爬虫总会遇到各种各样的反爬限制,反爬的第一道防线往往在登录就出现了,为了限制爬虫自动登录,各家使出了浑身解数,所谓道高一尺魔高一丈。 今天分享个如何简单处理滑动图片的验证码的案例。...
    99+
    2022-11-12
  • 如何使用Python实现极验验证码识别验证码
    这篇“如何使用Python实现极验验证码识别验证码”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“如何使用Python实现极验...
    99+
    2023-07-05
  • python 密码验证(滑块验证)
    目录题目描述:解题思路/算法分析/问题及解决实验代码题目描述: (1)模拟登陆界面,判别用户名和密码,给出合适的提示,如果超过三次,锁定输入。用代替密码;或者最新输入显示,前面的变成...
    99+
    2022-11-13
  • 【python 验证码】产生中文验证码
    #-*-coding:utf-8-*- import sys reload(sys) sys.setdefaultencoding('utf-8') from PIL import ImageDraw,ImageFont fro...
    99+
    2023-01-31
    验证码 中文 python
  • 如何利用html5 canvas破解简单验证码
    本篇内容主要讲解“如何利用html5 canvas破解简单验证码”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何利用html5 canvas破解简单验证码”吧...
    99+
    2022-10-19
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作