专栏名称: SegmentFault思否
SegmentFault (www.sf.gg)开发者社区,是中国年轻开发者喜爱的极客社区,我们为开发者提供最纯粹的技术交流和分享平台。
目录
相关文章推荐
程序猿  ·  41岁DeepMind天才科学家去世:长期受 ... ·  23 小时前  
程序员的那些事  ·  印度把 DeepSeek ... ·  2 天前  
OSC开源社区  ·  升级到Svelte ... ·  4 天前  
程序猿  ·  “我真的受够了Ubuntu!” ·  2 天前  
程序员小灰  ·  DeepSeek做AI代写,彻底爆了! ·  4 天前  
51好读  ›  专栏  ›  SegmentFault思否

开发必学的验证码,教你从零写一个验证码

SegmentFault思否  · 公众号  · 程序员  · 2019-08-31 10:00

正文



验证码是 web 开发中不可缺少的元素,而 python 又提供了非常多的验证码模块帮助大家快速生成各种验证码。


那你知道验证码生成的原理吗?所谓知其然,还要知其所以然。面试中,面试官不会因为你对框架很熟悉就夸赞你。


那今天小胖就带大家一层一层拨开验证码的衣服,看看其中的小奥秘 -

演示环境

  • 操作系统:windows10
  • thon 版本: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', (1080900), (255,255,255))

上面代码创建了一个亿 RGB 为颜色空间模式,尺寸为 1080*900,背景颜色为白色的图片。


2. Image.save(): 保存图片到本地

  • fp: 本地文件名
  • format: 可选参数,制定文件后缀名。

from PIL import Image

captcha = Image.new('RGB', (1080900), (255,255,255))

# captcha.save('captcha.png')
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', (1080900), 'red')
draw = ImageDraw.Draw(captcha)

上面就创建了一个在captcha这张图片上的画笔,我们在这个图片上画任何东西都会使用这个 画笔对象。


6. ImageDraw.Draw().text():在图片上绘制给定的字符

from PIL import Image, ImageDraw, ImageFont

captcha = Image.new('RGB', (1080900), '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', (1080900), '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', (1080900), '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=(255255255), 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(0150), random.randint(0150), random.randint(0150))
    return font_color

4. 随机获取干扰线条的颜色

def get_line_color(self):
    line_color = (random.randint(0250), random.randint(0255), random.randint(0250))
    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)
        # 绘制text
        draw.text(position, value, font=font, fill=self.get_font_color())
        # 改变下一个字符的开始绘制位置






请到「今天看啥」查看全文