Python生成验证码(可画干扰线、噪点)

1.写作由来

最近练习做一个电商项目,在注册页面准备加一个验证码功能。之前虽然也写过一个简单的验证码生成函数,但如今来看,真是有些‘勉强’,于是结合网上的一些文章,重新改良了一番。

2.实现思路

2.1制作验证码,我们首先得把验证码所必须的元素搞清楚。下面是我认为必需的一些参数。

参数名参数含义
width生成图片的宽度
height生成图片的高度
bgColor生成图片的背景色
num验证码字符个数
fontPath字体路径
fontSize字体大小
code验证码内容(作为返回值,用于验证)
img生成图片对象
savePath生成图片的保存路径

2.2弄清楚参数,还要考虑下验证码的呈现方式。如:字符随机产生、颜色随机更换、字符位置随机改变、干扰线的数量、噪点的数量…考虑清楚这些,便可以着手敲代码了。

3.代码实现

# coding:utf-8
import random
import os
import string
import json
from PIL import Image, ImageDraw, ImageFont

# 将随机函数赋给变量 rdint
rdint = random.randint

class vertifyCode():
    def __init__(self, width, height, bgColor, num, fontPath, fontSize, savePath):
        self.width = width  # 生成图片宽度
        self.height = height  # 生成图片高度
        self.bgColor = bgColor  # 生成图片背景颜色
        self.num = num  # 验证码字符个数
        self.fontPath = fontPath  # 字体路径
        self.fontSzie = fontSize  # 字体大小
        self.code = ''  # 验证内容
        self.img = Image.new('RGB', (self.width, self.height), self.bgColor)  # 生成图片对象
        self.savePath = savePath #生成图片的保存路径

    # 获取随机颜色,RGB格式
    def get_random_Color(self):
        c1 = rdint(50, 150)
        c2 = rdint(50, 150)
        c3 = rdint(50, 150)
        return (c1, c2, c3)

    # 随机生成1位字符,作为验证码内容
    def get_random_char(self):
        c = ''.join(random.sample(string.ascii_letters + string.digits, 1))
        self.code += c
        return c

    # 生成随机位置(x,y)
    def get_random_xy(self):
        x = rdint(0, int(self.width))
        y = rdint(0, int(self.height))
        return (x, y)

    # 根据字体文件生成字体,无字体文件则生成默认字体
    def get_font(self):
        if self.fontPath:
            if os.path.exists(self.fontPath):
                if self.fontSzie and self.fontSzie > 0 and self.fontSzie < self.height:
                    size = self.fontSzie
                else:
                    size = rdint(int(self.height /1.5), int(self.height - 10))
                font = ImageFont.truetype(self.fontPath, size)
                return font
            raise Exception('字体文件不存在或路径错误', self.fontPath)
        return ImageFont.load_default().font

    # 图片旋转
    def rotate(self):
        deg = int(self.height / 3)  # 旋转角度
        self.img = self.img.rotate(rdint(0, deg), expand=0)

    # 画n条干扰线
    def drawLine(self, n):
        draw = ImageDraw.Draw(self.img)
        for i in range(n):
            draw.line([self.get_random_xy(), self.get_random_xy()],
                      self.get_random_Color())
        del draw

    # 画n个干扰点
    def drawPoint(self, n):
        draw = ImageDraw.Draw(self.img)
        for i in range(n):
            draw.point([self.get_random_xy()], self.get_random_Color())
        del draw

    # 写验证码内容
    def drawText(self, position, char, fillColor):
        draw = ImageDraw.Draw(self.img)
        draw.text(position, char, font=self.get_font(), fill=fillColor)
        del draw

    # 生成验证码图片,并返回图片对象
    def getVertifyImg(self):
        x_start = 2
        y_start = 0
        for i in range(self.num):
            x = x_start + i * int(self.width / (self.num))
            y = rdint(y_start, int(self.height / 3))
            self.drawText((x, y), self.get_random_char(),
                          self.get_random_Color())
        self.drawLine(3)
        self.drawPoint(60)
        return self.img

    # 将图片保存到内存,便于前台点击刷新
    # 将验证码保存到session中,返回内存中的图片数据
    def saveInMemory(self, request):
        img = self.getVertifyImg()
        request.session['code'] = self.code.lower()
        f = BytesIO()  # 开辟内存空间
        img.save(f, 'png')
        return f.getvalue()

    # 将图片保存在本地,并以json格式返回验证码内容
    def saveInLocal(self):
        img = self.getVertifyImg()
        try:
            img.save(self.savePath)
        except:
            raise NotADirectoryError('保存路径错误或不存在:' + self.savePath)
        return json.dumps({'code': self.code})

4.效果图

博主其他文章推荐:
[1] 【python实用特性】- 迭代、可迭代对象、迭代器

[2] 【python实用特性】- 列表生成式

[3] 【python实用特性】- yield生成器

[4] 【python实用特性】- 装饰器

[5] 【Matplotlib】-自定义坐标轴刻度完成20万+数据的可视化

[6] Python+selenium实现自动爬取实例

[7] python爬取豆瓣Top250-改进版

[8] requests使用cookie模拟登陆豆瓣

[9] requests使用session保持会话


版权声明:本文为Dick633原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。