在Python web中实现验证码图片代码分享


Posted in Python onNovember 09, 2017

系统版本: CentOS 7.4
Python版本: Python 3.6.1

在现在的WEB中,为了防止爬虫类程序提交表单,图片验证码是最常见也是最简单的应对方法之一。

1.验证码图片的生成

  在python中,图片验证码一般用PIL或者Pillow库实现,下面就是利用Pillow生成图片验证码的代码:

#!/usr/bin/env python3

#- * -coding: utf - 8 - * -#@Author: Yang#@ Time: 2017 / 11 / 06 1: 04
import random
from PIL
import Image, ImageDraw, ImageFont, ImageFilter
_letter_cases = "abcdefghjkmnpqrstuvwxy"#
小写字母, 去除可能干扰的i, l, o, z
_upper_cases = _letter_cases.upper()# 大写字母
_numbers = ''.join(map(str, range(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 = (230, 230, 230),
    fg_color = (18, 18, 18),
    font_size = 20,
    font_type = ‘/usr/share / fonts / dejavu / DejaVuSans - Bold.ttf',
    length = 4,
    draw_lines = True,
    n_line = (1, 2),
    draw_points = True,
    point_chance = 1):
  ''
'@
todo: 生成验证码图片@ param size: 图片的大小, 格式( 宽, 高), 默认为(120, 30)@ param chars: 
允许的字符集合, 格式字符串@ param img_type: 图片保存的格式, 默认为GIF, 可选的为GIF, JPEG, TIFF, 
PNG@ param mode: 图片模式, 默认为RGB@ param bg_color: 背景颜色, 默认为白色@ param fg_color: 前景色, 
验证码字符颜色, 默认为蓝色 #0000FF
  @param font_size: 验证码字体大小
  @param font_type: 验证码字体的详细路径,默认为 ae_AlArabiya.ttf
  @param length: 验证码字符个数
  @param draw_lines: 是否划干扰线
  @param n_lines: 干扰线的条数范围,格式元组,默认为(1, 2),只有draw_lines为True时有效
  @param draw_points: 是否画干扰点
  @param point_chance: 干扰点出现的概率,大小范围[0, 100]
  @return: [0]: PIL Image实例
  @return: [1]: 验证码图片中的字符串
  '''
  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)))# 大小限制在[0, 100]
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

if __name__ == '__main__':
  img, str = create_validate_code()
img.save('./test.gif', 'gif')

  最后的结果会返回一个元组,第一个返回值为一个Image类的实例,第二个返回值为验证码图片中的字符串,可以用于比对验证码是否正确。

生成的验证码图片效果:

在Python web中实现验证码图片代码分享

 但是需要注意一点,以上代码需要依赖于系统字体,如果 font_type设置不正确,就会抛出 OSError 异常。

在Python web中实现验证码图片代码分享

对于CenOS系统,字体文件一般在 /usr/share/fonts/dejavu/ 下, 如CentOS 7.4:

在Python web中实现验证码图片代码分享

从中随意选取一个即可。windows 下同理,只需将 font_type 设置成正确的字体路径即可, 如

font_type=r"C:\Windows\Fonts\Arial.ttf"

在Python web中实现验证码图片代码分享

2.如何在网页中显示验证码

  在上述代码中,验证码都是以文件的方式保存。如果要在web中使用验证码,不可能每次都先生成验证码图片,先保存到磁盘,再返回给前端 web。这样会增加磁盘的开销,另外频繁产生的验证码也会占用大量的磁盘空间。这时,可以使用 BytesIO 模块,使验证码图片的读写直接在内存中进行,并直接返回给前端。同时将正确验证码字符串存在session中,当用户提交表单时,就可以和session中的正确字符串作比较了。

  以Flask为例,以下为在Flask中使用验证码的完整 Demo:

#!/usr/bin/env python3
# -*- coding: utf-8 -*- 
# @Author : Yang
# @Time  : 2017/11/08 15:35 
import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter
from io import BytesIO
from flask import Flask, session, request
_letter_cases = "abcdefghjkmnpqrstuvwxy" # 小写字母,去除可能干扰的i,l,o,z
_upper_cases = _letter_cases.upper() # 大写字母
_numbers = ''.join(map(str, range(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=(230, 230, 230),
             fg_color=(18, 18, 18),
             font_size=20,
             font_type='/usr/share/fonts/dejavu/DejaVuSans-Bold.ttf',
             length=4,
             draw_lines=True,
             n_line=(1, 2),
             draw_points=True,
             point_chance=1):
  '''
  @todo: 生成验证码图片
  @param size: 图片的大小,格式(宽,高),默认为(120, 30)
  @param chars: 允许的字符集合,格式字符串
  @param img_type: 图片保存的格式,默认为GIF,可选的为GIF,JPEG,TIFF,PNG
  @param mode: 图片模式,默认为RGB
  @param bg_color: 背景颜色,默认为白色
  @param fg_color: 前景色,验证码字符颜色,默认为蓝色#0000FF
  @param font_size: 验证码字体大小
  @param font_type: 验证码字体的详细路径,默认为 ae_AlArabiya.ttf
  @param length: 验证码字符个数
  @param draw_lines: 是否划干扰线
  @param n_lines: 干扰线的条数范围,格式元组,默认为(1, 2),只有draw_lines为True时有效
  @param draw_points: 是否画干扰点
  @param point_chance: 干扰点出现的概率,大小范围[0, 100]
  @return: [0]: PIL Image实例
  @return: [1]: 验证码图片中的字符串
  '''
  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))) # 大小限制在[0, 100]
    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
app = Flask(__name__)
app.config.update(
  DEBUG=True,
  SECRET_KEY='...'
)
@app.route('/')
def index():
  return 'test'
@app.route('/code')
def get_code():
  # 把strs发给前端,或者在后台使用session保存
  code_img, strs = create_validate_code()
  buf = BytesIO()
  code_img.save(buf, 'jpeg')
  buf_str = buf.getvalue()
  response = app.make_response(buf_str)
  response.headers['Content-Type'] = 'image/gif'
  session['img'] = strs.upper()
  return response
@app.route("/login", methods=["POST", "GET"])
def login():
  if request.method == 'POST':
    if session.get('img') == request.form.get('img').upper():
      return 'OK'
    return 'Error'
  return """
  <form action="" method="post">
    <p>Name:<input type=text name=username>
    <p>Password:<input type=text name=password>
    <p>CAPTCHA:<input type=text name=img>
    <img id="verficode" src="./code" onclick="this.src='./code?'+Math.random()">    # onclick事件用于每次
点击时获取一个新的验证码
    <p><input type=submit value=Login>
  </form>
  """
if __name__ == "__main__":
  app.run(host="0.0.0.0", port=18888, debug=True)

最终效果:

在Python web中实现验证码图片代码分享

总结

以上就是本文关于在Python web中实现验证码图片代码分享的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:python实现人脸识别代码、Python爬虫实例爬取网站搞笑段子、Python入门之三角函数全解【收藏】等,有什么问题可以随时留言,小编会及时回复大家的。感谢朋友们对本站的支持!

Python 相关文章推荐
python双向链表实现实例代码
Nov 21 Python
Python实现删除文件中含“指定内容”的行示例
Jun 09 Python
利用 python 对目录下的文件进行过滤删除
Dec 27 Python
Python实现的三层BP神经网络算法示例
Feb 07 Python
python ipset管理 增删白名单的方法
Jan 14 Python
在Pycharm中对代码进行注释和缩进的方法详解
Jan 20 Python
Django使用中间键实现csrf认证详解
Jul 22 Python
python matplotlib库绘制散点图例题解析
Aug 10 Python
解析Python3中的Import
Oct 13 Python
python代码能做成软件吗
Jul 24 Python
python 输入字符串生成所有有效的IP地址(LeetCode 93号题)
Oct 15 Python
详解Pytorch显存动态分配规律探索
Nov 17 Python
Python模糊查询本地文件夹去除文件后缀的实例(7行代码)
Nov 09 #Python
Python3.6 Schedule模块定时任务(实例讲解)
Nov 09 #Python
Python中scatter函数参数及用法详解
Nov 08 #Python
python实现人脸识别代码
Nov 08 #Python
python生成随机图形验证码详解
Nov 08 #Python
Python爬虫实例爬取网站搞笑段子
Nov 08 #Python
python执行使用shell命令方法分享
Nov 08 #Python
You might like
php实现用户在线时间统计详解
2011/10/08 PHP
linux系统下php安装mbstring扩展的二种方法
2014/01/20 PHP
php实现邮件发送并带有附件
2014/01/24 PHP
php中session_id()函数详细介绍,会话id生成过程及session id长度
2015/09/23 PHP
Yii框架通过请求组件处理get,post请求的方法分析
2019/09/03 PHP
laravel实现图片上传预览,及编辑时可更换图片,并实时变化的例子
2019/11/14 PHP
javascript attachEvent和addEventListener使用方法
2009/03/19 Javascript
JS小框架 fly javascript framework
2009/11/26 Javascript
js对象的比较
2011/02/26 Javascript
同域jQuery(跨)iframe操作DOM(示例代码)
2013/12/13 Javascript
jquery表单验证框架提供的身份证验证方法(示例代码)
2013/12/27 Javascript
生成二维码方法汇总
2014/12/26 Javascript
深入理解JavaScript系列(26):设计模式之构造函数模式详解
2015/03/03 Javascript
分享我对JS插件开发的一些感想和心得
2016/02/04 Javascript
使用JavaScript脚本判断页面是否在微信中被打开
2016/03/06 Javascript
easyui 中的datagrid跨页勾选问题的实现方法
2017/01/18 Javascript
jquery封装插件时匿名函数形参和实参的写法解释
2017/02/14 Javascript
javascript实现多张图片左右无缝滚动效果
2017/03/22 Javascript
详细教你微信公众号正文页SVG交互开发技巧
2019/07/25 Javascript
[01:08]2014DOTA2展望TI 剑指西雅图LGD战队专访
2014/06/30 DOTA
python解析json实例方法
2013/11/19 Python
python实现监控windows服务并自动启动服务示例
2014/04/17 Python
在python的WEB框架Flask中使用多个配置文件的解决方法
2014/04/18 Python
解决Python中字符串和数字拼接报错的方法
2016/10/23 Python
请不要重复犯我在学习Python和Linux系统上的错误
2016/12/12 Python
Python编写Windows Service服务程序
2018/01/04 Python
Pytorch模型迁移和迁移学习,导入部分模型参数的操作
2021/03/03 Python
使用HTML5捕捉音频与视频信息概述及实例
2018/08/22 HTML / CSS
瑞典时尚服装购物网站:Miinto.se
2017/10/30 全球购物
Chantelle仙黛尔内衣美国官网:法国第一品牌内衣
2018/07/26 全球购物
武夷山导游词
2015/02/03 职场文书
酒店辞职书怎么写
2015/02/26 职场文书
村官个人总结范文
2015/03/03 职场文书
毕业生个人自荐书
2015/03/05 职场文书
工作年限证明范本
2015/06/15 职场文书
Python面向对象编程之类的概念
2021/11/01 Python