Python案例实战:手把手教你用Pillow生成图片验证码(含完整代码+常见问题解析)
📖 目录导读
- 为什么需要图片验证码?
- 核心工具:Pillow库安装与基础用法
- 从零开始:生成简单字母数字验证码
- 进阶美化:添加干扰线、噪点、扭曲效果
- 实战案例:生成带颜色的随机验证码图片
- 常见问题问答(Q&A)
- SEO优化建议与搜索引擎排名要点
为什么需要图片验证码?
在互联网时代,图片验证码(CAPTCHA)是防止恶意爬虫、刷票、暴力破解等自动化攻击的常见手段,它通过生成带有扭曲、噪声的文本图像,要求用户手动输入,从而区分人类与机器,Python因其丰富的第三方库,成为实现验证码生成的首选语言。

经典场景:网站登录、注册表单、评论提交、API接口防刷等。
核心工具:Pillow库安装与基础用法
Python中生成图片验证码最成熟的库是 Pillow(PIL的分支)。
安装命令:
pip install Pillow
基础功能:
Image.new():创建空白画布ImageDraw.Draw:在图片上绘制文字、线条ImageFont.truetype:加载字体文件(支持TTF)random模块:生成随机颜色、字符
从零开始:生成简单字母数字验证码
以下代码生成4位随机字母+数字组合的验证码图片:
from PIL import Image, ImageDraw, ImageFont
import random
import string
# 设置参数
width, height = 160, 60
font_path = "arial.ttf" # 可替换为其他字体文件
font_size = 36
bg_color = (255, 255, 255) # 白色背景
# 生成随机4位字符(字母+数字)
def random_text(length=4):
return ''.join(random.choices(string.ascii_uppercase + string.digits, k=length))
# 创建画布
image = Image.new('RGB', (width, height), bg_color)
draw = ImageDraw.Draw(image)
font = ImageFont.truetype(font_path, font_size)
# 绘制验证码文字(每个字符颜色随机)
text = random_text()
x_start = 10
for char in text:
color = (random.randint(0, 200), random.randint(0, 200), random.randint(0, 200))
draw.text((x_start, 10), char, fill=color, font=font)
x_start += 35
image.save("simple_captcha.png")
输出效果:一张白底带4个彩色字符的图片,无干扰。
进阶美化:添加干扰线、噪点、扭曲效果
真实场景中,验证码必须增加干扰以提升破解难度:
from PIL import ImageFilter
# 添加干扰线(2条随机线条)
for _ in range(2):
start = (random.randint(0, width), random.randint(0, height))
end = (random.randint(0, width), random.randint(0, height))
draw.line([start, end], fill=(0, 0, 0), width=2)
# 添加噪点(随机像素点)
for _ in range(100):
x = random.randint(0, width-1)
y = random.randint(0, height-1)
image.putpixel((x, y), (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))
# 应用模糊滤镜(增加扭曲感)
image = image.filter(ImageFilter.BLUR)
image.save("enhanced_captcha.png")
关键点:线条和噪点颜色应尽量与文字色接近但不同,避免被简单过滤。
实战案例:生成带颜色的随机验证码图片
一个完整的验证码生成函数(可直接集成到Web应用):
def generate_captcha(text_length=4, width=160, height=50, font_path="arial.ttf"):
# 创建背景渐变(随机色)
from random import randint
bg_color_start = (randint(200, 255), randint(200, 255), randint(200, 255))
bg_color_end = (randint(100, 200), randint(100, 200), randint(100, 200))
image = Image.new('RGB', (width, height), bg_color_start)
draw = ImageDraw.Draw(image)
# 绘制垂直渐变背景(模拟)
for y in range(height):
ratio = y / height
r = int(bg_color_start[0] * (1 - ratio) + bg_color_end[0] * ratio)
g = int(bg_color_start[1] * (1 - ratio) + bg_color_end[1] * ratio)
b = int(bg_color_start[2] * (1 - ratio) + bg_color_end[2] * ratio)
draw.line([(0, y), (width, y)], fill=(r, g, b))
# 绘制文字(字符随机位置微调)
font = ImageFont.truetype(font_path, 28)
text = random_text(text_length)
x = 10
for char in text:
y_offset = randint(-5, 5) # 上下偏移
char_color = (randint(50, 180), randint(50, 180), randint(50, 180))
draw.text((x, 10 + y_offset), char, fill=char_color, font=font)
x += 35
# 干扰椭圆
for _ in range(3):
draw.ellipse([randint(0, width), randint(0, height),
randint(10, 60), randint(10, 60)],
outline=(randint(0, 100), randint(0, 100), randint(0, 100)))
# 保存为内存流(用于直接返回HTTP响应)
from io import BytesIO
buf = BytesIO()
image.save(buf, format='PNG')
buf.seek(0)
return buf, text # 返回图片字节流和真实验证码文本
# 使用示例
img_bytes, code_text = generate_captcha()
print(f"验证码文本: {code_text}")
应用集成:在Flask/Django中可直接返回img_bytes,并存储code_text到Session供验证。
常见问题问答(Q&A)
❓ Q1: 为什么生成的验证码字体显示为乱码或方块?
A: 通常是因为 字体路径错误 或 系统缺少对应字体,建议使用绝对路径,如 C:/Windows/Fonts/arial.ttf(Windows)或 /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf(Linux),也可下载免费字体文件(如simhei.ttf)放在项目目录。
❓ Q2: 如何让验证码更难被OCR识别?
A: 综合使用以下技术:
- 文字扭曲变形(可用
Image.transform) - 叠加多个透明层
- 随机字符间距和旋转角度
- 使用彩色斑点背景而非纯色
- 加入字符之间的粘连(字符重叠)
❓ Q3: 生成验证码后的图片流如何直接返回给前端?
A: 使用BytesIO将图片保存到内存,再通过Web框架的send_file或Response输出,例如Flask:
from flask import Flask, make_response
@app.route('/captcha')
def captcha():
img_bytes, code = generate_captcha()
response = make_response(img_bytes.getvalue())
response.headers['Content-Type'] = 'image/png'
return response
❓ Q4: 验证码文本需要区分大小写吗?
A: 通常忽略大小写,因为字母识别易混淆(如“0”与“O”),建议统一转大写存储,前端输入时自动转大写再比较。
SEO优化建议与搜索引擎排名要点
为了让本文在必应(Bing)和谷歌(Google)获得良好排名,需遵循以下规则:
包含核心关键词中“Python案例”、“生成图片验证码”直接命中用户搜索意图。
2. 使用H2/H3标签本文目录导读采用Markdown的、,搜索引擎会视为主标题结构。
3. 自然嵌入长尾关键词如“Pillow库验证码”、“Python验证码生成函数”、“网页验证码实现”。
4. 提供可复现的代码块搜索引擎偏好“解决实际问题”的内容,本文每段代码均需可独立运行。
5. 常见问答模块问答形式直接匹配用户搜索的疑问句式(如“怎么生成”、“为什么不行”)。
6. 内链与外链**(注意域名已按您要求修改):
- 内部链接:推荐相关文章如《Python图片处理大全》
- 外部链接:引用Pillow官方文档(如
pillow.readthedocs.io)
- 页面加载速度:本文代码块均用反引号包裹,避免大图片拖慢页面。
最终建议:在实际网站发布时,为每段代码添加<pre><code>标签,并增加文章摘要(meta description)如“本文详细讲解Python用Pillow生成图片验证码的完整案例,包含干扰线、扭曲、随机颜色等核心技巧,附Q&A解答常见错误。”
通过以上步骤,您已掌握Python生成图片验证码的完整技术栈,若需更复杂的动态验证码(如行为验证),可进一步研究captcha库或集成第三方服务。