怎么用Python实现随机生成图片验证码

发布时间:2022-01-19 13:29:22 作者:iii
来源:亿速云 阅读:179
# 怎么用Python实现随机生成图片验证码

## 引言

在当今互联网应用中,验证码(CAPTCHA)是防止恶意机器人和自动化脚本攻击的重要手段。图片验证码通过要求用户识别并输入扭曲或变形的字符来验证操作者是否为真人。本文将详细介绍如何使用Python生成随机图片验证码,涵盖从基础实现到高级定制的完整过程。

---

## 一、准备工作

### 1.1 所需工具库
生成图片验证码主要依赖以下Python库:
- **Pillow**:Python图像处理库(PIL的分支)
- **random**:生成随机字符和颜色
- **string**:提供字母和数字字符集
- **io**(可选):用于内存中处理图像流

安装Pillow:
```bash
pip install pillow

1.2 基础原理

验证码生成流程: 1. 创建空白画布 2. 生成随机字符 3. 绘制干扰元素(噪点、线条) 4. 输出图片或字节流


二、基础实现

2.1 生成空白画布

from PIL import Image, ImageDraw, ImageFont
import random
import string

def generate_captcha(width=120, height=40):
    # 创建RGB模式白色背景图
    image = Image.new('RGB', (width, height), (255, 255, 255))
    return image

2.2 添加随机文本

def add_text(image, length=4):
    draw = ImageDraw.Draw(image)
    
    # 字符集:数字+大写字母(排除易混淆字符)
    chars = string.digits + string.ascii_uppercase
    chars = chars.replace('0', '').replace('O', '').replace('1', '').replace('I', '')
    
    # 随机选择字符
    captcha_text = ''.join(random.choice(chars) for _ in range(length))
    
    # 加载字体(需提供字体文件路径)
    try:
        font = ImageFont.truetype('arial.ttf', 24)
    except:
        font = ImageFont.load_default()
    
    # 绘制每个字符(随机位置和颜色)
    for i, char in enumerate(captcha_text):
        x = 10 + i * 30 + random.randint(-5, 5)
        y = 5 + random.randint(-5, 5)
        color = (random.randint(0, 100), random.randint(0, 100), random.randint(0, 100)
        draw.text((x, y), char, fill=color, font=font)
    
    return image, captcha_text

2.3 添加干扰元素

def add_noise(image):
    draw = ImageDraw.Draw(image)
    width, height = image.size
    
    # 绘制干扰点
    for _ in range(100):
        x = random.randint(0, width)
        y = random.randint(0, height)
        draw.point((x, y), fill=(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))
    
    # 绘制干扰线
    for _ in range(3):
        x1 = random.randint(0, width)
        y1 = random.randint(0, height)
        x2 = random.randint(0, width)
        y2 = random.randint(0, height)
        draw.line((x1, y1, x2, y2), fill=(random.randint(0, 255), width=1)
    
    return image

2.4 完整调用示例

def simple_captcha():
    image = generate_captcha()
    image, text = add_text(image)
    image = add_noise(image)
    image.show()  # 显示图片
    print("验证码内容:", text)
    return image, text

三、进阶优化

3.1 扭曲变形(增强安全性)

使用Pillow的ImageTransform实现文字扭曲:

from PIL import ImageTransform

def distort_text(image):
    width, height = image.size
    # 创建正弦波变形
    distort = ImageTransform.QuadTransform(
        (0, 0, 0, height,  # 左上、左下
         width, 0, width + random.randint(-5, 5), height)  # 右上、右下
    )
    return image.transform(image.size, Image.QUAD, distort.getdata())

3.2 背景渐变

def gradient_background(image):
    draw = ImageDraw.Draw(image)
    width, height = image.size
    for y in range(height):
        # 从上到下的渐变
        r = int(255 * (y / height))
        g = random.randint(200, 255)
        b = int(255 * (1 - y / height)))
        draw.line((0, y, width, y), fill=(r, g, b))
    return image

3.3 动态字符间距

修改add_text()函数中的字符绘制部分:

x_offset = 10
for i, char in enumerate(captcha_text):
    # 动态调整间距(基于字符宽度)
    char_width = font.getsize(char)[0]
    x = x_offset + random.randint(-3, 3)
    y = 5 + random.randint(-5, 5)
    draw.text((x, y), char, fill=color, font=font)
    x_offset += char_width + random.randint(2, 8)

四、Web应用集成

4.1 生成验证码API(Flask示例)

from flask import Flask, make_response
import io

app = Flask(__name__)

@app.route('/captcha')
def get_captcha():
    image, text = simple_captcha()
    
    # 存储验证码文本(实际应使用Redis等存储)
    app.config['CAPTCHA_TEXT'] = text
    
    # 转换为字节流
    img_io = io.BytesIO()
    image.save(img_io, 'PNG')
    img_io.seek(0)
    
    response = make_response(img_io.getvalue())
    response.headers['Content-Type'] = 'image/png'
    return response

4.2 验证逻辑

@app.route('/verify', methods=['POST'])
def verify():
    user_input = request.form.get('captcha', '').upper()
    if user_input == app.config.get('CAPTCHA_TEXT', ''):
        return "验证成功"
    return "验证失败"

五、安全性增强建议

  1. 时效性控制:验证码应设置有效期(通常2-5分钟)
  2. 使用次数限制:每个验证码仅允许验证一次
  3. 日志监控:记录失败尝试次数,防止暴力破解
  4. 行为分析:结合鼠标轨迹等生物特征验证
  5. 多因素验证:对敏感操作使用短信+图片双验证

六、完整代码示例

import random
import string
from PIL import Image, ImageDraw, ImageFont, ImageFilter

class CaptchaGenerator:
    def __init__(self, width=160, height=60, char_length=6):
        self.width = width
        self.height = height
        self.char_length = char_length
        self._chars = self._get_valid_chars()
        
    def _get_valid_chars(self):
        """排除易混淆字符"""
        chars = string.digits + string.ascii_uppercase
        exclude = {'0', 'O', '1', 'I', 'L', '7', 'Z', '2', 'S', '5', 'B', '8'}
        return ''.join(c for c in chars if c not in exclude)
    
    def generate(self):
        # 创建渐变背景
        image = Image.new('RGB', (self.width, self.height), (255, 255, 255))
        draw = ImageDraw.Draw(image)
        for x in range(self.width):
            for y in range(self.height):
                r = x + y if (x + y < 255) else 255
                g = 255 - x if (255 - x > 0) else 0
                b = y
                draw.point((x, y), fill=(r, g, b))
        
        # 生成验证码文本
        captcha_text = ''.join(random.choice(self._chars) for _ in range(self.char_length))
        
        # 绘制文字(带扭曲)
        font_path = 'arial.ttf'  # 需替换实际路径
        try:
            font = ImageFont.truetype(font_path, 28)
        except:
            font = ImageFont.load_default()
            
        x_offset = 5
        for char in captcha_text:
            # 随机旋转角度
            char_image = Image.new('RGBA', (30, 40))
            char_draw = ImageDraw.Draw(char_image)
            char_draw.text((0, 0), char, font=font, fill=(random.randint(0, 180), 
                                                         random.randint(0, 180),
                                                         random.randint(0, 180)))
            
            # 随机旋转和变形
            char_image = char_image.rotate(random.randint(-30, 30), expand=1)
            char_image = char_image.resize((30, 40))
            
            # 粘贴到主图像
            y_offset = random.randint(0, 10)
            image.paste(char_image, (x_offset, y_offset), char_image)
            x_offset += 30 + random.randint(-5, 5)
        
        # 添加干扰
        self._add_noise(image)
        image = image.filter(ImageFilter.SMOOTH)
        
        return image, captcha_text
    
    def _add_noise(self, image):
        draw = ImageDraw.Draw(image)
        for _ in range(100):  # 干扰点
            x = random.randint(0, self.width)
            y = random.randint(0, self.height)
            draw.point((x, y), fill=(random.randint(0, 255), 
                                   random.randint(0, 255),
                                   random.randint(0, 255)))
        
        for _ in range(5):  # 干扰线
            x1 = random.randint(0, self.width)
            y1 = random.randint(0, self.height)
            x2 = random.randint(0, self.width)
            y2 = random.randint(0, self.height)
            draw.line((x1, y1, x2, y2), fill=(random.randint(0, 255),
                                            random.randint(0, 255),
                                            random.randint(0, 255)), width=1)

# 使用示例
if __name__ == '__main__':
    generator = CaptchaGenerator()
    image, text = generator.generate()
    image.save('captcha.png')
    print("生成的验证码:", text)

结语

本文从基础到进阶详细介绍了Python生成图片验证码的实现方法。实际应用中,建议: 1. 定期更换验证码样式 2. 结合后端逻辑进行严格验证 3. 根据业务需求调整复杂度

验证码技术需要与其它安全措施配合使用,才能构建更完善的防御体系。完整的项目代码已包含文中关键实现,读者可直接扩展使用。 “`

(注:实际字符数约2400字,包含代码示例和详细说明)

推荐阅读:
  1. 用python写个随机验证码
  2. 如何在Java中生成图片验证码

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

python

上一篇:如何分析SQL Server 数据库的设计

下一篇:html5中有哪些常用框架

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》