python生成验证码图片,结合接口供前端调用

  • 🌈所属专栏:【python】
  • 作者主页:  Mr.Zwq
  • ✔️个人简介:一个正在努力学技术的Python领域创作者,擅长爬虫,逆向,全栈方向,专注基础和实战分享,欢迎咨询!

您的点赞、关注、收藏、评论,是对我最大的激励和支持!!!🤩🥰😍

目录

效果展示

代码实现

注意

报错解决(没报错请忽略)

总结


效果展示


代码实现

直接复制使用即可

import random
import string
import os.path
from io import BytesIO
from PIL import Image
from PIL import ImageFilter
from PIL.ImageDraw import Draw
from PIL.ImageFont import truetype


class Bezier:
    def __init__(self):
        self.tsequence = tuple([t / 20.0 for t in range(21)])
        self.beziers = {}

    def pascal_row(self, n):
        """ Returns n-th row of Pascal's triangle
        """
        result = [1]
        x, numerator = 1, n
        for denominator in range(1, n // 2 + 1):
            x *= numerator
            x /= denominator
            result.append(x)
            numerator -= 1
        if n & 1 == 0:
            result.extend(reversed(result[:-1]))
        else:
            result.extend(reversed(result))
        return result

    def make_bezier(self, n):
        try:
            return self.beziers[n]
        except KeyError:
            combinations = self.pascal_row(n - 1)
            result = []
            for t in self.tsequence:
                tpowers = (t ** i for i in range(n))
                upowers = ((1 - t) ** i for i in range(n - 1, -1, -1))
                coefs = [c * a * b for c, a, b in zip(combinations,
                                                      tpowers, upowers)]
                result.append(coefs)
            self.beziers[n] = result
            return result


class Captcha(object):
    def __init__(self):
        self._bezier = Bezier()
        self._dir = os.path.dirname(__file__)
        # self._captcha_path = os.path.join(self._dir, '..', 'static', 'captcha')

    @staticmethod
    def instance():
        if not hasattr(Captcha, "_instance"):
            Captcha._instance = Captcha()
        return Captcha._instance

    def initialize(self, width=200, height=75, color=None, text=None, fonts=None):
        self._text = text if text else random.sample(string.ascii_uppercase + string.ascii_uppercase + '3456789', 4)
        self.fonts = fonts if fonts else \
            [os.path.join(self._dir, 'fonts', font) for font in os.listdir('fonts')]
        self.width = width
        self.height = height
        self._color = color if color else self.random_color(0, 200, random.randint(220, 255))

    @staticmethod
    def random_color(start, end, opacity=None):
        red = random.randint(start, end)
        green = random.randint(start, end)
        blue = random.randint(start, end)
        if opacity is None:
            return red, green, blue
        return red, green, blue, opacity

    # draw image

    def background(self, image):
        Draw(image).rectangle([(0, 0), image.size], fill=self.random_color(238, 255))
        return image

    @staticmethod
    def smooth(image):
        return image.filter(ImageFilter.SMOOTH)

    def curve(self, image, width=4, number=6, color=None):
        dx, height = image.size
        dx /= number
        path = [(dx * i, random.randint(0, height))
                for i in range(1, number)]
        bcoefs = self._bezier.make_bezier(number - 1)
        points = []
        for coefs in bcoefs:
            points.append(tuple(sum([coef * p for coef, p in zip(coefs, ps)])
                                for ps in zip(*path)))
        Draw(image).line(points, fill=color if color else self._color, width=width)
        return image

    def noise(self, image, number=50, level=2, color=None):
        width, height = image.size
        dx = width / 10
        width -= dx
        dy = height / 10
        height -= dy
        draw = Draw(image)
        for i in range(number):
            x = int(random.uniform(dx, width))
            y = int(random.uniform(dy, height))
            draw.line(((x, y), (x + level, y)), fill=color if color else self._color, width=level)
        return image

    def text(self, image, fonts, font_sizes=None, drawings=None, squeeze_factor=0.75, color=None):
        color = color if color else self._color
        fonts = tuple([truetype(name, size)
                       for name in fonts
                       for size in font_sizes or (65, 70, 75)])
        draw = Draw(image)
        char_images = []
        for c in self._text:
            font = random.choice(fonts)
            c_width, c_height = draw.textsize(c, font=font)
            char_image = Image.new('RGB', (c_width, c_height), (0, 0, 0))
            char_draw = Draw(char_image)
            char_draw.text((0, 0), c, font=font, fill=color)
            char_image = char_image.crop(char_image.getbbox())
            for drawing in drawings:
                d = getattr(self, drawing)
                char_image = d(char_image)
            char_images.append(char_image)
        width, height = image.size
        offset = int((width - sum(int(i.size[0] * squeeze_factor)
                                  for i in char_images[:-1]) -
                      char_images[-1].size[0]) / 2)
        for char_image in char_images:
            c_width, c_height = char_image.size
            mask = char_image.convert('L').point(lambda i: i * 1.97)
            image.paste(char_image,
                        (offset, int((height - c_height) / 2)),
                        mask)
            offset += int(c_width * squeeze_factor)
        return image

    # draw text
    @staticmethod
    def warp(image, dx_factor=0.27, dy_factor=0.21):
        width, height = image.size
        dx = width * dx_factor
        dy = height * dy_factor
        x1 = int(random.uniform(-dx, dx))
        y1 = int(random.uniform(-dy, dy))
        x2 = int(random.uniform(-dx, dx))
        y2 = int(random.uniform(-dy, dy))
        image2 = Image.new('RGB',
                           (width + abs(x1) + abs(x2),
                            height + abs(y1) + abs(y2)))
        image2.paste(image, (abs(x1), abs(y1)))
        width2, height2 = image2.size
        return image2.transform(
            (width, height), Image.QUAD,
            (x1, y1,
             -x1, height2 - y2,
             width2 + x2, height2 + y2,
             width2 - x2, -y1))

    @staticmethod
    def offset(image, dx_factor=0.1, dy_factor=0.2):
        width, height = image.size
        dx = int(random.random() * width * dx_factor)
        dy = int(random.random() * height * dy_factor)
        image2 = Image.new('RGB', (width + dx, height + dy))
        image2.paste(image, (dx, dy))
        return image2

    @staticmethod
    def rotate(image, angle=25):
        return image.rotate(
            random.uniform(-angle, angle), Image.BILINEAR, expand=1)

    def captcha(self, path=None, fmt='JPEG'):
        """Create a captcha.

        Args:
            path: save path, default None.
            fmt: image format, PNG / JPEG.
        Returns:
            A tuple, (name, text, StringIO.value).
            For example:
                ('fXZJN4AFxHGoU5mIlcsdOypa', 'JGW9', '\x89PNG\r\n\x1a\n\x00\x00\x00\r...')

        """
        image = Image.new('RGB', (self.width, self.height), (255, 255, 255))
        image = self.background(image)
        image = self.text(image, self.fonts, drawings=['warp', 'rotate', 'offset'])
        image = self.curve(image)
        image = self.noise(image)
        image = self.smooth(image)
        name = "".join(random.sample(string.ascii_lowercase + string.ascii_uppercase + '3456789', 24))
        text = "".join(self._text)
        out = BytesIO()
        image.save(out, format=fmt)
        if path:
            image.save(os.path.join(path, name), fmt)
        return name, text, out.getvalue()

    def generate_captcha(self):
        self.initialize()
        return self.captcha("")


captcha = Captcha.instance()

if __name__ == '__main__':
    # 调用该函数即可生成验证码图片
    # 返回结果是包含了3个参数的元组,分别是验证码图片的id、验证码文本、图片的二进制数据
    print(captcha.generate_captcha())

    # 测试生成10张验证码图片并保存
    for i in range(10):
        img = captcha.generate_captcha()
        with open(f'{i}.jpg', 'wb') as f:
            f.write(img[2])

通过调用 captcha.generate_captcha() 函数即可生成验证码图片。

代码运行输出:

 

注意

这里需要字体文件来生成验证码的文本。

将字体文件放在跟代码同一目录的fonts文件夹下,上述代码即是captcha.py文件内容,如:

字体文件可以自行去网上下载,或直接复制电脑自带的字体文件。

这里以window系统为例:

按照路径找到该Fonts文件夹

打开该Fonts文件夹,

 自行选择想要使用的字体样式文件复制到fonts文件夹下即可运行。


报错解决(没报错请忽略)

原因:pillow库版本太新,降低一些即可。

解决:

pip install pillow==9.5.0

总结

感谢观看,原创不易,如果觉得有帮助,请给文章点个赞吧,让更多的人看到。🌹🌹🌹

👍🏻也欢迎你,关注我。👍🏻

如有疑问,可在评论区留言哦~

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/712418.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

海外仓系统如何让海外仓受益,WMS海外仓系统使用指南

随着跨境电商业务的快速发展,海外仓面临着需要更加高速运转的巨大挑战。 当海外仓出现因为手动作业导致效率低下,成本不断飙升或者出现库存管理问题的时候,意味着是时候引入一套合适的海外仓管理系统了。 对于寻求海外仓业务流程优化的企业…

2779. 数组的最大美丽值

简单翻译一下题目意思: 对于每个 nums[i] 都可以被替换成 [nums[i]-k, nums[i]k] 区间中的任何数,区间左右是闭的。在每个数字可以替换的前提下,返回数组中最多的重复数字的数量。 第一想法是用一个哈希表,Key 是可以被替换的数…

设置SSHkeys多服务器免登录配置(ssh config)

一、背景: 多邮箱或者多git账号进行同一台电脑开发的情况。 有时候,开发时可能会面临一个情况,就是通过自己的电脑,可能同时需要开发多个不同地方的项目,或者说,自己建立的项目已经配置好SSH验证免密登录&a…

阿里云系列产品免费用,不香吗?

阿里云系列产品免费用,不香吗? 什么是无影云电脑开启无影云下载安装客户端登录无影云桌面应用场景 开篇先发布一下阿里云产品免费体验地址:https://free.aliyun.com/?utm_contentg_1000370296 下面开始我的无影云电脑或者叫做无影云桌面的体…

【scikit-learn入门指南】:机器学习从零开始

1. 简介 scikit-learn是一款用于数据挖掘和数据分析的简单高效的工具,基于NumPy、SciPy和Matplotlib构建。它能够进行各种机器学习任务,如分类、回归和聚类。 2. 安装scikit-learn 在开始使用scikit-learn之前,需要确保已经安装了scikit-le…

【会议征稿,IEEE出版】第六届物联网、自动化和人工智能国际学术会议(IoTAAI 2024,7月26-28)

第六届物联网、自动化和人工智能国际会议(IoTAAI 2024)将于2024年07月26-28日在中国广州召开。 会议旨在拓展国际科技学术交流渠道,搭建学术资源共享平台,促进全球范围内的科技创新,提升中外学术合作。会议还鼓励不同领…

免费的端口映射工具哪个好用

端口映射,即从一个网络环境下的端口映射到另一个网络环境下访问的过程。通常由软件方式来提供这一过程的实现,或一些客户端工具。当涉及内外网时,如内网端口地址映射到外网地址,即是内网穿透的原理。免费的端口映射工具有哪些&…

基于iBeacon蓝牙定位技术的反向寻车系统

随着城市化进程的加速和汽车保有量的不断增加,大型停车场成为了人们日常生活中不可或缺的一部分。然而,在繁忙的停车场中快速找到自己的车辆,成为了许多车主的难题。为了解决这一问题,维小帮基于iBeacon蓝牙技术打造的反向寻车系统…

C语言之常用字符串函数总结、使用和模拟实现

文章目录 目录 一、strlen 的使用和模拟实现 二、strcpy 的使用及模拟实现 三、strcat 的使用和模拟实现 四、strcmp 的使用和模拟实现 五、strncpy 的使用和模拟实现 六、strncat 的使用和模拟实现 七、strncmp 的使用和模拟实现 八、strstr 的使用和模拟实现 九、st…

Kafka中的时间轮算法

1. Kafka与时间轮: Kafka的定时器底层使用时间轮算法。Kafka时间轮是层次时间轮,并且支持时间轮复用。 优点: 高效的插入操作: 时间轮底层数据结构(桶),使用双向链表的设计使得插入操作的时间…

手机是如何实现多个应用程序同时运行的?

想要理解这个问题,我们要先了解一下操作系统以及进程相关的知识: 操作系统的功能有很多, 例如: 进程管理(Process Management): 功能:创建和终止进程,进程调度&#xf…

Android开发更改JDK版本

今天在跑GitHub上面一个Android项目时,在Android编译时出现如下错误: Unsupported Java. Your build is currently configured to use Java 17.0.2 and Gradle 7.0.2.错误原因: JDK和Gradle版本对应出错。 本地的JDK为1.8正好可以更改为本…

深入理解计算机系统 CSAPP 家庭作业6.34

第一步先求(S,E,B,m) 题目说共C32个字节,块大小B为16个字节,那就是分为两组:0,1.然后每组存4个int 每个4字节 CB*E*S .B16 ,直接映射的E就是1,所以S2 m为啥等于7? 通过写出两个数组所有的地址可以得出m7. 得出高速缓存的参数:(S,E,B,m)(2,1,16,7),注意图6-26每个参数的定义…

适合加密货币交易者的免费指标

本文介绍了7种用于分析加密货币市场的免费技术指标,帮助交易者和投资者提升交易技巧和盈利能力。原文: Best 7 Free Trading Indicators for Every Cryptocurrency Trader Austin Distel Unsplash 大家好!无论是加密货币市场的交易者还是投资者&#xff…

(Java微服务项目实战)dtpay聚合支付系统对账管理模块系统设计

1 聚合支付系统对账流程 dtpay聚合支付系统对账模块主要涵盖商户侧对账和渠道侧对账、平台侧对账,本文主要分析渠道侧对账。dtpay聚合支付系统通过支付渠道微信、支付宝等产生的支付退款交易数据需要和平台侧产生的数据进行交易数据比对。接下来我们具体分析对账流…

手把手教学部署前端项目到nginx

1.下载nginx 说明:下载11.20.2版本的nginx。 2.配置nginx 说明:找到conf目录下的nginx.conf文件。 2.1代理静态资源 说明:服务器块监听的端口为8089,意味着Nginx将在8089端口上接收和处理HTTP请求。root后面的值相当于html文…

实时交通 | 城市交通态势采集及可视化操作(定时运行)

一、前言 交通态势数据是关于交通状况的一种量化描述,它提供了关于道路网络运行状态的详细信息。交通态势数据指的是根据车流入量和车流出量的定义,衡量整个全局交通区域交通态势的数据。这些数据通常从车辆GPS轨迹数据中提取,包括车辆行驶速…

时代巨兽!深度神经网络如何改变我们的世界?

深度神经网络 1、 简介1.1 定义深度神经网络1.2 深度学习的发展历程1.3 深度神经网络的应用领域 2、深度神经网络的基本原理2.1 神经元层2.1.1 神经元2.1.2 神经元层 2.2 前向传播2.3 反向传播2.4 激活函数2.4.1、作用2.4.2、常见激活函数2.4.3、选择激活函数的考虑 2.5 损失函…

new Set( )的基本使用以及如何去重对象数组

目录 Set 对象方法 Set 对象作用 实现数组的去重 实现字符串的去重 实现并集 交集 差集 实现去重对象数组 相关参考资料 在 ES6 中,引入了一个新的数据结构类型:Set。而 Set 与 Array 的结构是很类似的,且 Set 和 Array 可以相互进…

MySQL学习——创建MySQL Workbench中的Connections

在MySQL Workbench中,Connections(连接)是用户与MySQL数据库进行交互的桥梁。 本文将添加一个新连接,该连接可以是初始连接,也可以是附加连接。在开始之前,必须安装、启动MySQL服务器的实例,并…