Better>>Me

导航

django网页图片验证码功能

在一个正常的登录系统中,验证码是非常重要的,用于识别人机,毕竟我们都知道,这个世界中存在着万恶的爬虫,验证码有很多种方式,有图片的,有邮件的,有短信的,有拼图的,不管什么样的验证码,目的都是验证访问用户到底是人还是机器,要对机器say no,接下来我们要实践一个图片性的验证码。

 

首先 ,先定义路由 urls.py下

url(r'^verify/(\d+)/(\d+)/$',views.verify),

 

 

1:

我们就要开始构造验证码函数了,也就是返回一张验证码图片的函数,怎么建呢?我们又没有验证码图片在?没有就直接画出来呗,python拥有一个库pillow专门用于画图的,

安装命令pip install pillow

 

  • 使用pillow画图,第一步就是创建一张画布,有了画布我们才可以在上面画画对不,创建画布代码如下
    # 创建画布需要导入`Image`包
     from PIL import Image
     # 用到了`Image`的`new`函数
     # 第一个参数是颜色通道,这里使用了RGB通道,还有其他的一些通道,如CMYK之类的,但不用管
     # 第二个参数是由宽高组成的元组,数字
     # 第三个参数是图片的背景色,这里用rgb的颜色显示,例如( 255, 255, 255),注意这是元组
     img = Image.new('RGB', (width, height), bgColor)

     

  • 有了画布,但我们用什么来画图,(难道是。。。画笔?),废话,当然是,来,给你支画笔
     # 创建画笔需要导入`ImageDraw`包
     from PIL import ImageDraw
     # 用到了`ImageDraw`的`Draw`函数
     # 有且只有一个参数,就是之前创建的画布
     draw = ImageDraw.Draw(img)
    View Code

     

  • 有了画布和画笔,但验证码中是有字的,难道我们真的要像现实一样一笔一划滴写字么,而且用电脑写好难看啊,其实pillow还可以导入电脑的字体,你不用再想些乱七八糟的东西了
    # 导入字体需要导入`ImageFont`包
     from PIL import ImageFont
     # 用到了`ImageFont`的`truetype`函数,可以自动查询电脑中的字体
     # 第一个参数是字体名字
     # 第二个参数是字体大小
     # 注意这个是windows系统下默认的字体,其他系统自己找
     font = ImageFont.truetype('arial.ttf', size)
    View Code

     

  • 好了准备工作都差不多了,开始画东西吧,首先得要有字
     # 写字需要使用`draw`的`text`方法
     # 第一个参数是一个坐标轴元组,分别是距离左边和上边的距离
     # 第二个参数是要写的字(字符串)
     # 后面的两个参数分别是字体和字体颜色
     draw.text((x, y), text, font=font, fill=textColor)
    View Code

     

  • 还有可能要一些干扰元素,例如线条
     # 画线条需要使用`draw`的`line`方法
     # 第一个参数是包含了两个坐标的元组,分别是线条一头一尾的坐标
     # 后面的参数是线条的颜色
     draw.line((x1, y1, x2, y2), fill=lineColor)
    View Code

 

好了开始写接口函数

from PIL import Image,ImageDraw,ImageFont #
from random import randint

def verify(request,width,height):
    wordsCount = 4 #验证码的长度
    width = int(width) #图片宽度
    height = int(height) #图片高度
    size = int(min(width/wordsCount,height)/1.5) #字体大小设置
    bgColor = (randint(200,255),randint(200,255),randint(200,255)) #随机背景色
    img = Image.new('RGB', (width, height),bgColor)  # 构建画布
    font = ImageFont.truetype('Arial.ttf',size)#导入字体
    draw = ImageDraw.Draw(img)  # 生成画笔

 

接下来我们要返回生成的图片

python有个内置模块StringIO,可以将图片缓存到内存里面,读取后就清空内存

例子

 # 导入StringIO模块
 from StringIO import StringIO
 # 建立一个缓存对象
 mstream = StringIO()
 # 将图片保存到内存中
 img.save(mstream, 'jpeg')
 # 返回内存中的图片
 return HttpResponse(mstream.getvalue(), 'image/jpeg')

 

定一个验证码的规则:

  • 规则一:均匀绘画字符,居中
  • 规则二:字符颜色要比较深
  • 规则三:要有线条雪花等干扰元素
  • 规则四:一切能随机的都随机

 

开始画

  • 首先要确定用什么字符,数字+大小写字母
     text = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'

     

  • 其次要确定文字的位置
     left = width * i / num + (width / 4 - size) / 2# i为第几个文字
     top = (height - size) / 2

     

  • 还要确定文字的颜色,要随机的颜色,颜色要比较深
     textColor = (randint(0, 160), randint(0, 160), randint(0, 160))

     

  • 合并
    text = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
     for i in range(wordsCount):
         textColor = (randint(0, 160), randint(0, 160), randint(0, 160))
         left = width * i / wordsCount + (width / 4 - size) / 2
         top = (height - size) / 2
         draw.text((left, top), text[randint(0, len(text) - 1)], font=font, fill=textColor)
    View Code

     

    再画雪花
  • 字体颜色

    textColor = (255, 255, 255)

     

  • 位置:随机
     left = randint(0, width)
     top = randint(0, height)

     

  • 合起来:
     for i in range(30):
         textColor = (255, 255, 255)
         left = randint(0, width)
         top = randint(0, height)
         draw.text((left, top), '*', font=font, fill=textColor)

     

最后画线条

  • 位置:头尾都随机
    line = (randint(0, width), randint(0, height), randint(0, width), randint(0, height))

     

  • 颜色随机
    linecolor = (randint(0, 160), randint(0, 160), randint(0, 160))

     

  • 合并:
     for i in range(5):
         linecolor = (randint(0, 160), randint(0, 160), randint(0, 160))
         line = (randint(0, width), randint(0, height), randint(0, width), randint(0, height))
         draw.line(line, fill=linecolor)

     

 

所有步骤合起来

# -*- coding:utf-8 -*-
 import sys
 reload(sys)
 sys.setdefaultencoding('utf-8')
 from django.http import HttpResponse
 from PIL import Image, ImageFont, ImageDraw
 from StringIO import StringIO
 from random import randint
 def verify(request, width, height):
     wordsCount = 4
     width = int(width)
     height = int(height)
     size = int(min(width / wordsCount, height) / 1.3)
     bgColor = (randint(200, 255), randint(200, 255), randint(200, 255))
     img = Image.new('RGB', (width, height), bgColor)
     font = ImageFont.truetype('arial.ttf', size)
     draw = ImageDraw.Draw(img)
     text = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
     for i in range(wordsCount):
         textColor = (randint(0, 160), randint(0, 160), randint(0, 160))
         left = width * i / wordsCount + (width / 4 - size) / 2
         top = (height - size) / 2
         draw.text((left, top), text[randint(0, len(text) - 1)], font=font, fill=textColor)
     for i in range(30):
         textColor = (255, 255, 255)
         left = randint(0, width)
         top = randint(0, height)
         draw.text((left, top), '*', font=font, fill=textColor)
     for i in range(5):
         linecolor = (randint(0, 160), randint(0, 160), randint(0, 160))
         line = (randint(0, width), randint(0, height), randint(0, width), randint(0, height))
         draw.line(line, fill=linecolor)
     del draw
     mstream = StringIO()
     img.save(mstream, 'jpeg')
     return HttpResponse(mstream.getvalue(), 'image/jpeg')
View Code

访问一下

localhost:8000/verify/100/40/

看到我们生成的验证码了!

然后进行验证功能

将生成的字符保存到 request.session['key'] 里就好了

如果出现一下问题则可以参考

 

 

使用request.session的时候出现了这种出错,google一下,发现是django旧版本的问题,新版本中的

MIDDLEWARE 被替换成了MIDDLEWARE_CLASSES 名字改掉后,ok!

该教程参照简书:http://www.jianshu.com/p/7795783979da

posted on 2017-04-01 16:32  Better>>Me  阅读(738)  评论(0编辑  收藏  举报