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素数检测的方法
May 11 Python
Python的Django框架中自定义模版标签的示例
Jul 20 Python
Python错误提示:[Errno 24] Too many open files的分析与解决
Feb 16 Python
Unicode和Python的中文处理
Mar 19 Python
PyTorch上搭建简单神经网络实现回归和分类的示例
Apr 28 Python
查看django版本的方法分享
May 14 Python
在python中使用requests 模拟浏览器发送请求数据的方法
Dec 26 Python
Django框架会话技术实例分析【Cookie与Session】
May 24 Python
Python自定义一个异常类的方法
Jun 27 Python
Python FtpLib模块应用操作详解
Dec 12 Python
python自然语言处理之字典树知识总结
Apr 25 Python
使用python创建股票的时间序列可视化分析
Mar 03 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获取汉字拼音首字母的方法
2015/10/21 PHP
PHP实现的DES加密解密类定义与用法示例
2020/11/02 PHP
js动态在form上插入enctype=multipart/form-data的问题
2012/05/24 Javascript
js+html+css实现鼠标移动div实例
2013/01/30 Javascript
网站如何做到完全不需要jQuery也可以满足简单需求
2013/06/27 Javascript
jquery设置元素的readonly和disabled的写法
2013/09/22 Javascript
利用window.name实现windowStorage代码分享
2014/01/02 Javascript
Nodejs学习笔记之NET模块
2015/01/13 NodeJs
JQuery复制DOM节点的方法
2015/06/11 Javascript
JavaScript在网页中画圆的函数arc使用方法
2015/11/13 Javascript
基于javascript简单实现对身份证校验
2021/01/25 Javascript
Bootstrap表格使用方法详解
2017/02/17 Javascript
video.js使用改变ui过程
2017/03/05 Javascript
从零开始学习Node.js系列教程四:多页面实现数学运算的client端和server端示例
2017/04/13 Javascript
jQuery扇形定时器插件pietimer使用方法详解
2017/07/18 jQuery
nodejs Assert中equal(),strictEqual(),deepEqual(),strictDeepEqual()比较
2017/09/18 NodeJs
jQuery实现的两种简单弹窗效果示例
2018/04/18 jQuery
Vue 之孙组件向爷组件通信的实现
2019/04/23 Javascript
layui使用数据表格实现购物车功能
2019/07/26 Javascript
es6函数之尾递归用法实例分析
2020/04/25 Javascript
[23:18]Spirit vs Liquid Supermajor小组赛A组 BO3 第二场 6.2
2018/06/03 DOTA
python中使用OpenCV进行人脸检测的例子
2014/04/18 Python
Python实现动态加载模块、类、函数的方法分析
2017/07/18 Python
python实现网页自动签到功能
2019/01/21 Python
jupyter notebook 的工作空间设置操作
2020/04/20 Python
css3中单位px,em,rem,vh,vw,vmin,vmax的区别及浏览器支持情况
2016/12/06 HTML / CSS
Melijoe英国官网:法国儿童时尚网站
2016/11/18 全球购物
美国体育用品商店:Paragon Sports
2017/10/08 全球购物
英国皇家造币厂:The Royal Mint
2018/10/05 全球购物
教师个人自我鉴定
2014/02/08 职场文书
借款协议书
2014/04/12 职场文书
优秀应届本科生求职信
2014/07/19 职场文书
2014离婚协议书范文两篇
2014/09/15 职场文书
开展党的群众路线教育实践活动个人对照检查材料
2014/11/05 职场文书
2015年银行客户经理工作总结
2015/04/01 职场文书
村党组织公开承诺书
2015/04/30 职场文书