福利干货,第一时间送达!
本文授权转载自Python专栏,禁二次转载
验证码是web开发中不可缺少的元素,而python又提供了非常多的验证码模块帮助大家快速生成各种验证码。
那你知道验证码生成的原理吗?所谓知其然,还要知其所以然。面试中,面试官不会因为你对框架很熟悉就夸赞你。
那今天小胖就带大家一层一层拨开验证码的衣服,看看其中的小奥秘 -<-
演示环境
- 操作系统:
windows10
- python版本:
python 3.7
- 代码编辑器:
pycharm 2018.2
- 使用第三方模块:
pillow
验证码的必须元素
1. 一张图片
2. 文本
3. 干扰元素
- 线条干扰
- 小圆点干扰
熟悉pillow库
我们既然需要使用pillow库制作验证码,那么首先我们先来熟悉一下我们需要用到的方法。
1. Image.new(): 这个方法可以生成一张图片,有三个参数。
- mode:颜色空间模式,可以是`'RGBA','RGB','L'`等等模式
- size:图片尺寸,接收一个两个整数的元祖
- color:图片的填充颜色,可以是`red,green`等,也可以是rgb的三个整数的元祖。
也就是背景颜色
from PIL
import Image
captcha = Image.new(
'RGB', (
1080,
900), (
255,
255,
255))
上面代码创建了一个亿RGB为颜色空间模式,尺寸为1080*900,背景颜色为白色的图片。
2. Image.save(): 保存图片到本地
- fp: 本地文件名
- format: 可选参数,制定文件后缀名。
from PIL
import Image
captcha = Image.new(
'RGB', (
1080,
900), (
255,
255,
255))
captcha.save(
'captcha', format=
'png')
上面两种方式保存效果是一样的。
3. Image.show():显示图片,会调用电脑自带的显示图片的软件。
4. ImageFont.truetype(): 加载一个字体文件。
生成一个字体对象。
from PIL
import ImageFont
font = ImageFont.truetype(
'simkai.ttf',
16)
5. ImageDraw.Draw(): 生成画笔对象。
from PIL
import Image, ImageDraw
captcha = Image.new(
'RGB', (
1080,
900),
'red')
draw = ImageDraw.Draw(captcha)
上面就创建了一个在captcha这张图片上的画笔,我们在这个图片上画任何东西都会使用这个画笔对象。
6. ImageDraw.Draw().text():在图片上绘制给定的字符
from PIL
import Image, ImageDraw, ImageFont
captcha = Image.new(
'RGB', (
1080,
900),
'red')
font = ImageFont.truetype(
'simkai.ttf',
16)
draw = ImageDraw.Draw(captcha)
draw.text((
0,
0),
'hello world', font=font, fill=
'black')
7. ImageDraw.Draw().line():在图片上绘制线条
from PIL
import Image, ImageDraw, ImageFont
captcha = Image.new(
'RGB', (
1080,
900),
'red')
draw = ImageDraw.Draw(captcha)
draw.line([(
0,
0),(
1080,
900)], fill=
'black')
8. ImageDraw.Draw().point(): 在图片上绘制点
from PIL
import Image, ImageDraw, ImageFont
captcha = Image.new(
'RGB', (
1080,
900),
'red')
font = ImageFont.truetype(
'simkai.ttf',
16)
draw = ImageDraw.Draw(captcha)
draw.point((
500,
500), fill=
'black')
制作我们的验证码我们就会使用到上面的方法。
当然,pillow肯定不止这些方法,这里我们就只列举这些了。
制作验证码
1. 首先我们定义一个类,初始化一些需要的参数。
import string
class Captcha():
'''
captcha_size: 验证码图片尺寸
font_size: 字体大小
text_number: 验证码中字符个数
line_number: 线条个数
background_color: 验证码的背景颜色
sources: 取样字符集。验证码中的字符就是随机从这个里面选取的
save_format: 验证码保存格式
'''
def __init__(self, captcha_size=(150,100), font_size=30,text_number=4, line_number=4, background_color=(255, 255, 255), sources=None, save_format='png'):
self.text_number = text_number
self.line_number = line_number
self.captcha_size = captcha_size
self.background_color = background_color
self.font_size = font_size
self.format = save_format
if sources:
self.sources = sources
else:
self.sources = string.ascii_letters + string.digits
这里说一下string模块。
- string.ascii_letters: 得到a-zA-Z所有字符
- string.digits: 得到0-9所有数字
2. 随机从sources获取字符
import random
def get_text(self):
text = random.sample(self.sources,k=self.text_number)
return
''.join(text)
random.sample()方法:
从第一个参数中随机获取字符。
获取个数有第二个参数指定。
3. 随机获取绘制字符的颜色
def get_font_color(self):
font_color = (random.randint(
0,
150), random.randint(
0,
150), random.randint(
0,
150))
return font_color
4. 随机获取干扰线条的颜色
def get_line_color(self):
line_color = (random.randint(
0,
250), random.randint(
0,
255), random.randint(
0,
250))
return line_color
5. 编写绘制文字的方法
def draw_text(self,draw, text, font, captcha_width, captcha_height, spacing=20):
'''
在图片上绘制传入的字符
:param draw: 画笔对象
:param text: 绘制的所有字符
:param font: 字体对象
:param captcha_width: 验证码的宽度
:param captcha_height: 验证码的高度
:param spacing: 每个字符的间隙
:return:
'''
text_width, text_height = font.getsize(text)
every_value_width = int(text_width /
4)
text_length = len(text)
total_spacing = (text_length
-1) * spacing
if total_spacing + text_width >= captcha_width:
raise ValueError(
"字体加中间空隙超过图片宽度!")
start_width = int( (captcha_width - text_width - total_spacing) /
2 )
start_height = int( (captcha_height - text_height) /
2 )
for value
in text:
position = start_width, start_height
print(position)
draw.text(position, value, font=font, fill=self.get_font_color())
start_width = start_width + every_value_width + spacing
6. 绘制线条的方法
def draw_line(self, draw, captcha_width, captcha_height):
'''
绘制线条
:param draw: 画笔对象
:param captcha_width: 验证码的宽度
:param captcha_height: 验证码的高度
:return:
'''
begin = (random.randint(
0,captcha_width/
2), random.randint(
0, captcha_height))
end = (random.randint(captcha_width/
2,captcha_width), random.randint(
0, captcha_height))
draw.line([begin, end], fill=self.get_line_color())
7. 绘制小圆点
def draw_point(self, draw, point_chance, width, height):
'''
绘制小圆点
:param draw: 画笔对象
:param point_chance: 绘制小圆点的几率 概率为 point_chance/100
:param width: 验证码宽度
:param height: 验证码高度
:return:
'''
for w
in range(width):
for h
in range(height):
tmp = random.randint(
0,
100)
if tmp < point_chance:
draw.point((w, h), fill=self.get_line_color())
8. 制作验证码
def make_captcha(self):
width, height = self.captcha_size
captcha = Image.new(
'RGB',self.captcha_size,self.background_color)
font = ImageFont.truetype(
'simkai.ttf',self.font_size)
draw = ImageDraw.Draw(captcha)
text = self.get_text(
self.draw_text(draw, text, font, width, height)
for i
in range(self.line_number):
self.draw_line(draw, width, height)
self.draw_point(draw,
10,width,height)
captcha.save(
'captcha',format=self.format)
captcha.show()
这样,我们就生成了我们的图片验证码了,效果图:
后台回复
关键字
「
验证码
」
,获取完整代码
~
老表的福利是什么?
a.每天选择一条走心留言
赠书一本
(一般在推文头条(第一条)
文末有赠送书籍介绍
有前一天获奖读者信息)
b.留言打卡,满30天
进老表学习福利群
书籍、现金、课程统统安排
(在当天推文的任何一条留言
就算当天打卡成功)