利用Python破解验证码实例详解


Posted in Python onDecember 08, 2016

一、前言

本实验将通过一个简单的例子来讲解破解验证码的原理,将学习和实践以下知识点:

      Python基本知识

      PIL模块的使用

二、实例详解

安装 pillow(PIL)库:

$ sudo apt-get update

$ sudo apt-get install python-dev

$ sudo apt-get install libtiff5-dev libjpeg8-dev zlib1g-dev \
libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev python-tk

$ sudo pip install pillow

下载实验用的文件:

$ wget http://labfile.oss.aliyuncs.com/courses/364/python_captcha.zip
$ unzip python_captcha.zip
$ cd python_captcha

这是我们实验使用的验证码 captcha.gif

利用Python破解验证码实例详解

提取文本图片

在工作目录下新建 crack.py 文件,进行编辑。

#-*- coding:utf8 -*-
from PIL import Image

im = Image.open("captcha.gif")
#(将图片转换为8位像素模式)
im = 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]

颜色直方图的每一位数字都代表了在图片中含有对应位的颜色的像素的数量。

每个像素点可表现256种颜色,你会发现白点是最多(白色序号255的位置,也就是最后一位,可以看到,有625个白色像素)。红像素在序号200左右,我们可以通过排序,得到有用的颜色。

his = im.histogram()
values = {}

for i in range(256):
 values[i] = his[i]

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

我们得到了图片中最多的10种颜色,其中 220 与 227 才是我们需要的红色和灰色,可以通过这一讯息构造一种黑白二值图片。

#-*- coding:utf8 -*-
from PIL import Image

im = Image.open("captcha.gif")
im = im.convert("P")
im2 = Image.new("P",im.size,255)


for x in range(im.size[1]):
 for y in range(im.size[0]):
  pix = im.getpixel((y,x))
  if pix == 220 or pix == 227: # these are the numbers to get
   im2.putpixel((y,x),0)

im2.show()

得到的结果:

利用Python破解验证码实例详解

提取单个字符图片

接下来的工作是要得到单个字符的像素集合,由于例子比较简单,我们对其进行纵向切割:

inletter = False
foundletter=False
start = 0
end = 0

letters = []

for y in range(im2.size[0]): 
 for x in range(im2.size[1]):
  pix = im2.getpixel((y,x))
  if pix != 255:
   inletter = True
 if foundletter == False and inletter == True:
  foundletter = True
  start = y

 if foundletter == True and inletter == False:
  foundletter = False
  end = y
  letters.append((start,end))

 inletter=False
print letters

输出:

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

得到每个字符开始和结束的列序号。

import hashlib
import time

count = 0
for letter in letters:
 m = hashlib.md5()
 im3 = im2.crop(( letter[0] , 0, letter[1],im2.size[1] ))
 m.update("%s%s"%(time.time(),count))
 im3.save("./%s.gif"%(m.hexdigest()))
 count += 1

(接上面的代码)

对图片进行切割,得到每个字符所在的那部分图片。

AI 与向量空间图像识别

在这里我们使用向量空间搜索引擎来做字符识别,它具有很多优点:

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

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

向量空间搜索引擎名字听上去很高大上其实原理很简单。拿文章里的例子来说:

你有 3 篇文档,我们要怎么计算它们之间的相似度呢?2 篇文档所使用的相同的单词越多,那这两篇文章就越相似!但是这单词太多怎么办,就由我们来选择几个关键单词,选择的单词又被称作特征,每一个特征就好比空间中的一个维度(x,y,z 等),一组特征就是一个矢量,每一个文档我们都能得到这么一个矢量,只要计算矢量之间的夹角就能得到文章的相似度了。

用 Python 类实现向量空间:

import math

class VectorCompare:
 #计算矢量大小
 def magnitude(self,concordance):
  total = 0
  for word,count in concordance.iteritems():
   total += count ** 2
  return math.sqrt(total)

 #计算矢量之间的 cos 值
 def relation(self,concordance1, concordance2):
  relevance = 0
  topvalue = 0
  for word, count in concordance1.iteritems():
   if concordance2.has_key(word):
    topvalue += count * concordance2[word]
  return topvalue / (self.magnitude(concordance1) * self.magnitude(concordance2))

它会比较两个 python 字典类型并输出它们的相似度(用 0~1 的数字表示)

将之前的内容放在一起

还有取大量验证码提取单个字符图片作为训练集合的工作,但只要是有好好读上文的同学就一定知道这些工作要怎么做,在这里就略去了。可以直接使用提供的训练集合来进行下面的操作。

iconset目录下放的是我们的训练集。

最后追加的内容:

#将图片转换为矢量
def buildvector(im):
 d1 = {}
 count = 0
 for i in im.getdata():
  d1[count] = i
  count += 1
 return d1

v = VectorCompare()

iconset = ['0','1','2','3','4','5','6','7','8','9','0','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 = []
for letter in iconset:
 for img in os.listdir('./iconset/%s/'%(letter)):
  temp = []
  if img != "Thumbs.db" and img != ".DS_Store":
   temp.append(buildvector(Image.open("./iconset/%s/%s"%(letter,img))))
  imageset.append({letter:temp})


count = 0
#对验证码图片进行切割
for letter in letters:
 m = hashlib.md5()
 im3 = im2.crop(( letter[0] , 0, letter[1],im2.size[1] ))

 guess = []

 #将切割得到的验证码小片段与每个训练片段进行比较
 for image in imageset:
  for x,y in image.iteritems():
   if len(y) != 0:
    guess.append( ( v.relation(y[0],buildvector(im3)),x) )

 guess.sort(reverse=True)
 print "",guess[0]
 count += 1

得到结果

一切准备就绪,运行我们的代码试试:

python crack.py

输出

(0.96376811594202894, '7')
(0.96234028545977002, 's')
(0.9286884286888929, '9')
(0.98350370609844473, 't')
(0.96751165072506273, '9')
(0.96989711688772628, 'j')

是正解,干得漂亮。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

Python 相关文章推荐
简单掌握Python中glob模块查找文件路径的用法
Jul 05 Python
python机器学习实战之K均值聚类
Dec 20 Python
python的re正则表达式实例代码
Jan 24 Python
python 利用栈和队列模拟递归的过程
May 29 Python
使用Python来开发微信功能
Jun 13 Python
详解Python解决抓取内容乱码问题(decode和encode解码)
Mar 29 Python
python字典setdefault方法和get方法使用实例
Dec 25 Python
Pycharm远程连接服务器并实现代码同步上传更新功能
Feb 25 Python
Python Selenium破解滑块验证码最新版(GEETEST95%以上通过率)
Jan 29 Python
Jupyter Notebook内使用argparse报错的解决方案
Jun 03 Python
Python使用Web框架Flask开发项目
Jun 01 Python
Pytorch中expand()的使用(扩展某个维度)
Jul 15 Python
详解使用python crontab设置linux定时任务
Dec 08 #Python
Python 正则表达式入门(中级篇)
Dec 07 #Python
Python 正则表达式入门(初级篇)
Dec 07 #Python
Python标准库06之子进程 (subprocess包) 详解
Dec 07 #Python
利用 Monkey 命令操作屏幕快速滑动
Dec 07 #Python
Python深入06——python的内存管理详解
Dec 07 #Python
Python制作钉钉加密/解密工具
Dec 07 #Python
You might like
推荐文章系统(一)
2006/10/09 PHP
php操作csv文件代码实例汇总
2014/09/22 PHP
php blowfish加密解密算法
2016/07/02 PHP
PHP-FPM运行状态的实时查看及监控详解
2016/11/18 PHP
PHP基于关联数组20行代码搞定约瑟夫问题示例
2017/11/07 PHP
Linux下源码包安装Swoole及基本使用操作图文详解
2019/04/02 PHP
CentOS7编译安装php7.1的教程详解
2019/04/18 PHP
javascript innerHTML使用分析
2010/12/03 Javascript
js 获取页面高度和宽度兼容 ie firefox chrome等
2014/05/14 Javascript
JS实现跟随鼠标闪烁转动色块的方法
2015/02/26 Javascript
JS自动倒计时30秒后按钮才可用(两种场景)
2015/08/31 Javascript
jQuery滚动加载图片实现原理
2015/12/14 Javascript
老生常谈JavaScript数组的用法
2016/06/10 Javascript
javascript类型系统_正则表达式RegExp类型详解
2016/06/24 Javascript
完美解决jQuery符号$与其他javascript 库、框架冲突的问题
2016/08/09 Javascript
动态加载css方法实现和深入解析
2017/01/18 Javascript
解决html-jquery/js引用外部图片时遇到看不了或出现403的问题
2017/09/22 jQuery
JavaScript原型对象、构造函数和实例对象功能与用法详解
2018/08/04 Javascript
优雅的elementUI table单元格可编辑实现方法详解
2018/12/23 Javascript
js尾调用优化的实现
2019/05/23 Javascript
解决VUE项目localhost端口服务器拒绝连接,只能用127.0.0.1的问题
2020/08/14 Javascript
Python访问纯真IP数据库脚本分享
2015/06/29 Python
Python实现的概率分布运算操作示例
2017/08/14 Python
numpy np.newaxis 的实用分享
2019/11/30 Python
解决windows上安装tensorflow时报错,“DLL load failed: 找不到指定的模块”的问题
2020/05/20 Python
浅谈CSS3 动画卡顿解决方案
2019/01/02 HTML / CSS
美国知名的女性服饰品牌:LOFT(洛芙特)
2016/08/05 全球购物
Boutique 1美国:阿联酋奢侈时尚零售商
2017/10/16 全球购物
小学岗位竞聘方案
2014/01/22 职场文书
助人为乐道德模范事迹材料
2014/08/16 职场文书
研究生简历自我评
2015/03/11 职场文书
成品仓库管理员岗位职责
2015/04/09 职场文书
爱护环境卫生倡议书
2015/04/29 职场文书
2015年社区平安建设工作总结
2015/05/13 职场文书
2015秋季开学典礼新闻稿
2015/07/17 职场文书
vue实现无缝轮播效果(跑马灯)
2021/05/14 Vue.js