Python使用PIL库实现验证码图片的方法


Posted in Python onMarch 11, 2016

本文实例讲述了Python使用PIL库实现验证码图片的方法。分享给大家供大家参考,具体如下:

现在的网页中,为了防止机器人提交表单,图片验证码是很常见的应对手段之一。这里就不详细介绍了,相信大家都遇到过。

现在就给出用Python的PIL库实现验证码图片的代码。代码中有详细注释。

#!/usr/bin/env python
#coding=utf-8
import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter
_letter_cases = "abcdefghjkmnpqrstuvwxy" # 小写字母,去除可能干扰的i,l,o,z
_upper_cases = _letter_cases.upper() # 大写字母
_numbers = ''.join(map(str, range(3, 10))) # 数字
init_chars = ''.join((_letter_cases, _upper_cases, _numbers))
def create_validate_code(size=(120, 30),
             chars=init_chars,
             img_type="GIF",
             mode="RGB",
             bg_color=(255, 255, 255),
             fg_color=(0, 0, 255),
             font_size=18,
             font_type="ae_AlArabiya.ttf",
             length=4,
             draw_lines=True,
             n_line=(1, 2),
             draw_points=True,
             point_chance = 2):
  '''
  @todo: 生成验证码图片
  @param size: 图片的大小,格式(宽,高),默认为(120, 30)
  @param chars: 允许的字符集合,格式字符串
  @param img_type: 图片保存的格式,默认为GIF,可选的为GIF,JPEG,TIFF,PNG
  @param mode: 图片模式,默认为RGB
  @param bg_color: 背景颜色,默认为白色
  @param fg_color: 前景色,验证码字符颜色,默认为蓝色#0000FF
  @param font_size: 验证码字体大小
  @param font_type: 验证码字体,默认为 ae_AlArabiya.ttf
  @param length: 验证码字符个数
  @param draw_lines: 是否划干扰线
  @param n_lines: 干扰线的条数范围,格式元组,默认为(1, 2),只有draw_lines为True时有效
  @param draw_points: 是否画干扰点
  @param point_chance: 干扰点出现的概率,大小范围[0, 100]
  @return: [0]: PIL Image实例
  @return: [1]: 验证码图片中的字符串
  '''
  width, height = size # 宽, 高
  img = Image.new(mode, size, bg_color) # 创建图形
  draw = ImageDraw.Draw(img) # 创建画笔
  def get_chars():
    '''生成给定长度的字符串,返回列表格式'''
    return random.sample(chars, length)
  def create_lines():
    '''绘制干扰线'''
    line_num = random.randint(*n_line) # 干扰线条数
    for i in range(line_num):
      # 起始点
      begin = (random.randint(0, size[0]), random.randint(0, size[1]))
      #结束点
      end = (random.randint(0, size[0]), random.randint(0, size[1]))
      draw.line([begin, end], fill=(0, 0, 0))
  def create_points():
    '''绘制干扰点'''
    chance = min(100, max(0, int(point_chance))) # 大小限制在[0, 100]
    for w in xrange(width):
      for h in xrange(height):
        tmp = random.randint(0, 100)
        if tmp > 100 - chance:
          draw.point((w, h), fill=(0, 0, 0))
  def create_strs():
    '''绘制验证码字符'''
    c_chars = get_chars()
    strs = ' %s ' % ' '.join(c_chars) # 每个字符前后以空格隔开
    font = ImageFont.truetype(font_type, font_size)
    font_width, font_height = font.getsize(strs)
    draw.text(((width - font_width) / 3, (height - font_height) / 3),
          strs, font=font, fill=fg_color)
    return ''.join(c_chars)
  if draw_lines:
    create_lines()
  if draw_points:
    create_points()
  strs = create_strs()
  # 图形扭曲参数
  params = [1 - float(random.randint(1, 2)) / 100,
       0,
       0,
       0,
       1 - float(random.randint(1, 10)) / 100,
       float(random.randint(1, 2)) / 500,
       0.001,
       float(random.randint(1, 2)) / 500
       ]
  img = img.transform(size, Image.PERSPECTIVE, params) # 创建扭曲
  img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # 滤镜,边界加强(阈值更大)
  return img, strs
if __name__ == "__main__":
  code_img = create_validate_code()
  code_img.save("validate.gif", "GIF")

最后结果返回一个元组,第一个返回值是Image类的实例,第二个参数是图片中的字符串(比较是否正确的作用)。

最后结果返回一个元组,第一个返回值是Image类的实例,第二个参数是图片中的字符串(比较是否正确的作用)。

需要提醒的是,如果在生成ImageFont.truetype实例的时候抛出IOError异常,有可能是运行代码的电脑没有包含指定的字体,需要下载安装。

生成的验证码图片效果:

Python使用PIL库实现验证码图片的方法

这时候,细心的同学可能要问,如果每次生成验证码,都要先保存生成的图片,再显示到页面。这么做让人太不能接受了。这个时候,我们需要使用python内置的StringIO模块,它有着类似file对象的行为,但是它操作的是内存文件。于是,我们可以这么写代码:

try:
  import cStringIO as StringIO
except ImportError:
  import StringIO
mstream = StringIO.StringIO()
img = create_validate_code()[0]
img.save(mstream, "GIF")

这样,我们需要输出的图片的时候只要使用“mstream.getvalue()”即可。比如在Django里,我们首先定义这样的url:

from django.conf.urls.defaults import *
urlpatterns = patterns('example.views',
  url(r'^validate/$', 'validate', name='validate'),
)

在views中,我们把正确的字符串保存在session中,这样当用户提交表单的时候,就可以和session中的正确字符串进行比较。

from django.shortcuts import HttpResponse
from validate import create_validate_code
def validate(request):
  mstream = StringIO.StringIO()
  validate_code = create_validate_code()
  img = validate_code[0]
  img.save(mstream, "GIF")
  request.session['validate'] = validate_code[1]
  return HttpResponse(mstream.getvalue(), "image/gif")

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
Python内置的字符串处理函数详细整理(覆盖日常所用)
Aug 19 Python
简单介绍Ruby中的CGI编程
Apr 10 Python
Python import用法以及与from...import的区别
May 28 Python
python字典键值对的添加和遍历方法
Sep 11 Python
python3操作mysql数据库的方法
Jun 23 Python
pandas进行时间数据的转换和计算时间差并提取年月日
Jul 06 Python
使用Python和OpenCV检测图像中的物体并将物体裁剪下来
Oct 30 Python
Python实现图片裁剪的两种方式(Pillow和OpenCV)
Oct 30 Python
Python获取二维数组的行列数的2种方法
Feb 11 Python
Python爬取阿拉丁统计信息过程图解
May 12 Python
Python单元测试及unittest框架用法实例解析
Jul 09 Python
分享一枚pycharm激活码适用所有pycharm版本我的pycharm2020.2.3激活成功
Nov 20 Python
Python2.x利用commands模块执行Linux shell命令
Mar 11 #Python
Python实现列表转换成字典数据结构的方法
Mar 11 #Python
python中enumerate函数遍历元素用法分析
Mar 11 #Python
python实现class对象转换成json/字典的方法
Mar 11 #Python
Windows下Python的Django框架环境部署及应用编写入门
Mar 10 #Python
深入学习python的yield和generator
Mar 10 #Python
Python中random模块生成随机数详解
Mar 10 #Python
You might like
php cookie 作用范围?不要在当前页面使用你的cookie
2009/03/24 PHP
PHP 执行系统外部命令 system() exec() passthru()
2009/08/11 PHP
php 问卷调查结果统计
2015/10/08 PHP
PHP二分查找算法示例【递归与非递归方法】
2016/09/29 PHP
PHP实现的最大正向匹配算法示例
2017/12/19 PHP
lnmp安装多版本PHP共存的方法详解
2018/08/02 PHP
tp5(thinkPHP5框架)使用DB实现批量删除功能示例
2019/05/28 PHP
js 页面传参数时 参数值含特殊字符的问题
2009/12/13 Javascript
Extjs TriggerField在弹出窗口显示不出问题的解决方法
2010/01/08 Javascript
详细介绍8款超实用JavaScript框架
2013/10/25 Javascript
判断客户浏览器是否支持cookie的示例代码
2013/12/23 Javascript
javascript实现类似java中getClass()得到对象类名的方法
2015/07/27 Javascript
javascript实现动态标签云
2015/10/16 Javascript
js如何打印object对象
2015/10/16 Javascript
JQuery datepicker 用法详解
2015/12/25 Javascript
socket.io实现在线群聊功能
2017/04/07 Javascript
微信小程序中上传图片并进行压缩的实现代码
2018/08/28 Javascript
vue给对象动态添加属性和值的实例
2019/09/09 Javascript
Javascript 关于基本类型和引用类型的个人理解
2019/11/01 Javascript
[02:41]DOTA2英雄基础教程 亚巴顿
2014/01/02 DOTA
[01:03:27]NAVI vs EG 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/17 DOTA
paramiko模块安装和使用(远程登录服务器)
2014/01/27 Python
Python异常学习笔记
2015/02/03 Python
Python使用cx_Oracle模块将oracle中数据导出到csv文件的方法
2015/05/16 Python
python修改操作系统时间的方法
2015/05/18 Python
Python实现网站注册验证码生成类
2017/06/08 Python
解决yum对python依赖版本问题
2019/07/05 Python
Python3 使用pillow库生成随机验证码
2019/08/26 Python
通过python实现windows桌面截图代码实例
2020/01/17 Python
如何在 Django 模板中输出 "{{"
2020/01/24 Python
Python实现上下文管理器的方法
2020/08/07 Python
如何基于pandas读取csv后合并两个股票
2020/09/25 Python
html5 canvas实现圆形时钟代码分享
2013/12/25 HTML / CSS
实例教程 HTML5 Canvas 超炫酷烟花绽放动画实现代码
2014/11/05 HTML / CSS
2014年入党积极分子党校培训心得体会
2014/07/08 职场文书
水知道答案观后感
2015/06/08 职场文书