Python使用PIL库实现验证码图片生成与Web集成
介绍如何利用Python的PIL库编写自定义验证码生成函数,支持字符集、尺寸、字体及干扰元素参数配置。提供将验证码直接保存为文件以及在Django等Web框架中使用StringIO模块在内存中动态输出图片的完整代码示例,并附带字体缺失报错的排查方法。
验证码生成的核心逻辑与参数设计
利用Python进行图形验证码开发的本质是在内存中创建一个画布,随机选取目标长度的字符集合(大小写字母与数字),调用PIL的绘图接口完成渲染。为避免机器识别,通常需叠加干扰线、随机噪点,并施加透视变换与边缘增强滤镜增加OCR提取难度。整个流程可通过封装函数实现参数化控制,便于在不同业务场景中灵活调整安全级别与视觉风格。
第1步:准备开发环境与依赖包
验证码渲染依赖第三方图像处理库。执行以下命令安装或升级至支持现代Python环境的版本:
- 打开终端或命令行工具
- 运行
pip install Pillow获取最新官方镜像 - 验证导入无报错:
from PIL import Image, ImageDraw, ImageFont, ImageFilter
确认环境就绪后,可创建主脚本文件引入核心生成逻辑。
第2步:编写带参数的验证码生成函数
以下为经过兼容性优化的核心代码。已修正原示例中的老旧语法,并完善中文注释说明各入参的作用域与默认值:
# coding=utf-8
import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter
_letter_cases = "abcdefghjkmnpqrstuvwxy"
_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):
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)))
for w in range(width):
for h in range(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
第3步:本地调试保存图片并观察效果
初次接入时可直接在脚本末尾添加运行入口,将返回的Image对象写入磁盘进行视觉核对。完成后会生成一张GIF格式的静态帧图片:
if __name__ == "__main__":
code_img = create_validate_code()
code_img.save("validate.gif", "GIF")
生成的验证码图片效果:

第4步:在Django中通过内存流动态输出
生产环境中频繁读写磁盘会导致性能瓶颈。Python内置的 StringIO 模块提供类文件接口的内存缓冲区,配合 img.save() 可实现零I/O的HTTP响应流式传输。
Django路由配置(以现代路径写法为例):
# urls.py
from django.urls import path
from . import views
urlpatterns = [
path('validate/', views.validate, name='validate'),
]
视图层处理逻辑:
# views.py
from django.shortcuts import HttpResponse
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
from validate import create_validate_code
def validate(request):
mstream = 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")
上述操作将正确的校验码存入当前会话,前端表单提交后只需比对 request.POST['captcha_input'] 与 request.session.get('validate') 即可判定合法性。调用方通过 mstream.getvalue() 可直接获取字节流数据。
常见问题排查:字体加载失败的应对策略
执行 ImageFont.truetype() 时若抛出 IOError 或 FileNotFoundError,根本原因是宿主机系统未预装代码中指定的字形文件。解决方法如下:
- 登录服务器或开发机,检查指定路径下是否存在
.ttf后缀的有效字体 - 若无对应文件,可从操作系统字体库复制通用字体(如 Windows 的
Arial.ttf,Linux 的DejaVuSans.ttf)替换传入路径 - 修改参数后重新运行,确保控制台无回溯堆栈且能正常返回 Image 实例
以上就是基于Python的PIL库实现验证码图片生成与Django部署的详细内容,更多关于Python图像处理与Web后端开发资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













