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之传说中的函数编写条规
Oct 11 Python
python判断字符串是否包含子字符串的方法
Mar 24 Python
对Python新手编程过程中如何规避一些常见问题的建议
Apr 01 Python
Python获取暗黑破坏神3战网前1000命位玩家的英雄技能统计
Jul 04 Python
一个基于flask的web应用诞生 记录用户账户登录状态(6)
Apr 11 Python
Odoo中如何生成唯一不重复的序列号详解
Feb 10 Python
Python使用Matplotlib模块时坐标轴标题中文及各种特殊符号显示方法
May 04 Python
解决Python找不到ssl模块问题 No module named _ssl的方法
Apr 29 Python
利用PyQt中的QThread类实现多线程
Feb 18 Python
浅谈Python中文件夹和python package包的区别
Jun 01 Python
python相对企业语言优势在哪
Jun 12 Python
pycharm进入时每次都是insert模式的解决方式
Feb 05 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
PHP4实际应用经验篇(6)
2006/10/09 PHP
有道搜索和IP138的IP的API接口(PHP应用)
2012/11/29 PHP
解析php中static,const与define的使用区别
2013/06/18 PHP
关于实现代码语法标亮 dp.SyntaxHighlighter
2007/02/02 Javascript
jquery validate poshytip 自定义样式
2012/11/26 Javascript
js分页代码分享
2014/04/28 Javascript
js 通过cookie实现刷新不变化树形菜单
2014/10/30 Javascript
Javascript中的数据类型之旅
2015/10/18 Javascript
浅析node连接数据库(express+mysql)
2015/11/30 Javascript
Easyui form combobox省市区三级联动
2016/01/13 Javascript
后端接收不到AngularJs中$http.post发送的数据原因分析及解决办法
2016/07/05 Javascript
jquery实现拖动效果
2016/08/10 Javascript
select隐藏选中值对应的id,显示其它id的简单实现方法
2016/08/25 Javascript
浅谈Web页面向后台提交数据的方式和选择
2016/09/23 Javascript
javascript淘宝主图放大镜功能
2016/10/20 Javascript
AngularJS框架中的双向数据绑定机制详解【减少需要重复的开发代码量】
2017/01/19 Javascript
深入理解javascript的getTime()方法
2017/02/16 Javascript
vue的keep-alive用法技巧
2019/08/15 Javascript
js判断一个对象是数组(函数)的方法实例
2019/12/19 Javascript
[03:43]TI9战队采访——PSG.LGD
2019/08/22 DOTA
python实现图片批量剪切示例
2014/03/25 Python
Python2/3中urllib库的一些常见用法
2017/12/19 Python
python实现守护进程、守护线程、守护非守护并行
2018/05/05 Python
opencv3/C++实现视频背景去除建模(BSM)
2019/12/11 Python
解决pycharm安装第三方库失败的问题
2020/05/09 Python
python集合能干吗
2020/07/19 Python
Python进行统计建模
2020/08/10 Python
numpy实现RNN原理实现
2021/03/02 Python
CSS3中HSL和HSLA的简单使用示例
2015/07/14 HTML / CSS
AmazeUI中模态框的实现
2020/08/19 HTML / CSS
美丽的珠宝配饰:SmallThings
2019/09/04 全球购物
英国婚礼商城:Wedding Mall
2019/11/02 全球购物
linux面试题参考答案(7)
2014/07/24 面试题
安全伴我行演讲稿
2014/09/04 职场文书
2014卖家双十一活动策划书
2014/09/29 职场文书
JavaScript 原型与原型链详情
2021/11/02 Javascript