zoukankan      html  css  js  c++  java
  • Python生成随机验证码

    Python生成随机验证码,需要使用PIL模块.

    安装:

    1
    pip3 install pillow

    基本使用

    1
    2
    3
    4
    5
    6
    def check_code(request):
        #Django imag标签src属性导入图片的原理
        f=open('static/imgs/1.jpg','rb')    #注意:static/imgs/1.jpg不能写成 /static/imgs/1.jpg
        data=f.read()
        f.close()
        return HttpResponse(data)

    写入本地并读取到内存中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    def check_code(request):
        #创建code.png写入到本地目录下
        from PIL import Image
        img=Image.new(mode='RGB',size=(120,30),color=(255,255,255)) #默认写入白板,随后在白板上写入字符串等
        f=open('code.png','wb')
        img.save(f,'png')   #png为图片后缀
        f.close()
        #将本地图片code.png读取到内存并使网页图片能显示出来
        f=open('code.png','rb')
        data=f.read()
        f.close()
        return HttpResponse(data)

    以上操作比较麻烦,需要写入本地又读取到内存中

    优化:直接在内存中开辟空间,在内存中进行读写等操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    def check_code(request):   
        from io import BytesIO
        #写入内存中
        f=BytesIO()
        img=Image.new(mode='RGB',size=(120,30),color=(255,255,255))
        img.save(f,'png')
        #从内存中读出来
        data=f.getvalue()
        return HttpResponse(data)

    1. 创建图片

    1
    2
    3
    4
    5
    6
    7
    8
    9
    from PIL import Image
    img = Image.new(mode='RGB', size=(120, 30), color=(255, 255, 255))
      
    # 在图片查看器中打开
    # img.show()
      
    # 保存在本地
    with open('code.png','wb') as f:
        img.save(f,format='png')

    2. 创建画笔,用于在图片上画任意内容

    1
    2
    img = Image.new(mode='RGB', size=(120, 30), color=(255, 255, 255))
    draw = ImageDraw.Draw(img, mode='RGB')

    3. 画点

    1
    2
    3
    4
    5
    6
    img = Image.new(mode='RGB', size=(120, 30), color=(255, 255, 255))
    draw = ImageDraw.Draw(img, mode='RGB')
    # 第一个参数:表示坐标
    # 第二个参数:表示颜色
    draw.point([100, 100], fill="red")
    draw.point([300, 300], fill=(255, 255, 255))

    4. 画线

    1
    2
    3
    4
    5
    6
    img = Image.new(mode='RGB', size=(120, 30), color=(255, 255, 255))
    draw = ImageDraw.Draw(img, mode='RGB')
    # 第一个参数:表示起始坐标和结束坐标
    # 第二个参数:表示颜色
    draw.line((100,100,100,300), fill='red')
    draw.line((100,100,300,100), fill=(255, 255, 255))

    5. 画圆

    1
    2
    3
    4
    5
    6
    7
    img = Image.new(mode='RGB', size=(120, 30), color=(255, 255, 255))
    draw = ImageDraw.Draw(img, mode='RGB')
    # 第一个参数:表示起始坐标和结束坐标(圆要画在其中间)
    # 第二个参数:表示开始角度
    # 第三个参数:表示结束角度
    # 第四个参数:表示颜色
    draw.arc((100,100,300,300),0,90,fill="red")

    6. 写文本

    1
    2
    3
    4
    5
    6
    img = Image.new(mode='RGB', size=(120, 30), color=(255, 255, 255))
    draw = ImageDraw.Draw(img, mode='RGB')
    # 第一个参数:表示起始坐标
    # 第二个参数:表示写入内容
    # 第三个参数:表示颜色
    draw.text([0,0],'python',"red")

    7. 特殊字体文字

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    img = Image.new(mode='RGB', size=(120, 30), color=(255, 255, 255))
    draw = ImageDraw.Draw(img, mode='RGB')
    # 第一个参数:表示字体文件路径
    # 第二个参数:表示字体大小
    font = ImageFont.truetype("kumo.ttf", 28)
    # 第一个参数:表示起始坐标
    # 第二个参数:表示写入内容
    # 第三个参数:表示颜色
    # 第四个参数:表示颜色
    draw.text([0, 0], 'python', "red", font=font)

    图片验证码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    import random
      
    def check_code(width=120, height=30, char_length=5, font_file='kumo.ttf', font_size=28):
        code = []
        img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255))
        draw = ImageDraw.Draw(img, mode='RGB')
      
        def rndChar():
            """
            生成随机字母  
            :return:
            """
            return chr(random.randint(65, 90))
      
        def rndColor():
            """
            生成随机颜色
            :return:
            """
            return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))
      
        # 写文字
        font = ImageFont.truetype(font_file, font_size)
        for i in range(char_length):
            char = rndChar()
            code.append(char)
            h = random.randint(0, 4)
            draw.text([i * width / char_length, h], char, font=font, fill=rndColor())
      
        # 写干扰点
        for i in range(40):
            draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
      
        # 写干扰圆圈
        for i in range(40):
            draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
            x = random.randint(0, width)
            y = random.randint(0, height)
            draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor())
      
        # 画干扰线
        for i in range(5):
            x1 = random.randint(0, width)
            y1 = random.randint(0, height)
            x2 = random.randint(0, width)
            y2 = random.randint(0, height)
      
            draw.line((x1, y1, x2, y2), fill=rndColor())
      
        img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
        return img,''.join(code)
      
      
    if __name__ == '__main__':
        # 1. 直接打开
        # img,code = check_code()
        # img.show()
      
        # 2. 写入文件
        # img,code = check_code()
        # with open('code.png','wb') as f:
        #     img.save(f,format='png')
      
        # 3. 写入内存(Python3)
        # from io import BytesIO
        # stream = BytesIO()
        # img.save(stream, 'png')
        # stream.getvalue()
      
        # 4. 写入内存(Python2)
        # import StringIO
        # stream = StringIO.StringIO()
        # img.save(stream, 'png')
        # stream.getvalue()

      

    总结:当作模板使用

    方法一:

    #登录页面
    def login(request):
    
        if request.method=='POST':
            input_username=request.POST.get('user')
            input_pwd=request.POST.get('pwd')
            input_code=request.POST.get('code')
            session_code=request.session.get('code')
            print(input_code,session_code)
    
            if models.UserInfo.objects.filter(username=input_username,password=input_pwd).first():
                if input_code.upper() == session_code.upper():
                    return render(request,'information.html')
        return render(request,'login.html')
    
    
    
    
    
    #生成随机验证码
    from PIL import Image
    from io import BytesIO
    from PIL import ImageDraw,ImageFont
    def check_code(request):
    
        # #Django imag标签src属性导入图片的原理
        # f=open('static/imgs/1.jpg','rb')    #注意:static/imgs/1.jpg不能写成 /static/imgs/1.jpg
        # data=f.read()
        # f.close()
        # return HttpResponse(data)
        #创建code.png写入到本地BBS目录下
        # from PIL import Image
        # img=Image.new(mode='RGB',size=(120,30),color=(255,255,255)) #默认写入白板,随后在白板上写入字符串等
        # f=open('code.png','wb')
        # img.save(f,'png')   #png为图片后缀
        # f.close()
        # #将本地图片code.png读取到内存并使网页图片能显示出来
        # f=open('code.png','rb')
        # data=f.read()
        # f.close()
        # return HttpResponse(data)
        #以上操作比较麻烦,需要写入本地又读取到内存中
        #以下操作为在内存中开辟空间,在内存中进行读写等操作
        # from io import BytesIO
        # #写入内存中
        # f=BytesIO()
        # img=Image.new(mode='RGB',size=(120,30),color=(255,255,255))
        # img.save(f,'png')
        # #从内存中读出来
        # data=f.getvalue()
        # return HttpResponse(data)
    
        # from io import BytesIO
        # from PIL import ImageDraw,ImageFont
        f=BytesIO()
        img=Image.new(mode='RGB',size=(120,30),color=(255,255,255))
        draw=ImageDraw.Draw(img,mode='RGB')
        # draw.point([100, 25], fill="red")
        # draw.point([30, 20], fill=(187, 255, 255))
        # draw.line((10, 10, 20, 30), fill='red')
        # draw.line((100, 10, 30, 20), fill=(180, 255, 255))
        # draw.arc((30, 25, 80, 10), 0, 360, fill="red")
        # font = ImageFont.truetype("kumo.ttf", 28)
        # draw.text([0, 0], 'python', "red",font=font)
        import random
        # char_list=[]
        # for i in range(5):
        #     char=chr(random.randint(65,109))
        #     char_list.append(char)
        # ''.join(char_list)
        # #列表生成式,但是字母随机了,字体颜色不随机,所以不用列表生成式
        # v=''.join([ chr(random.randint(65,109)) for i in range(5)])
        # for i in range(5):
        #     char=chr(random.randint(65,109))
        #     font=ImageFont.truetype("kumo.ttf", 28)
        #     draw.text([i*24,0],char,(random.randint(0,255),random.randint(0,255),random.randint(0,255)),font=font)
        #写入的字符串需要自己知道内容,方便表单的校验
        # char_list = []
        # for i in range(5):
        #     char=chr(random.randint(65,109))
        #     char_list.append(char)
        #     font=ImageFont.truetype("kumo.ttf", 28)
        #     draw.text([i*24,0],char,(random.randint(0,255),random.randint(0,255),random.randint(0,255)),font=font)
        # code=''.join(char_list)
        #但又面临的问题是POST请求时提交数据,获取不到,所以需要写入session里,并进入login函数中增加POST请求
        # char_list = []
        # for i in range(5):
        #     char = chr(random.randint(65, 109))
        #     char_list.append(char)
        #     font = ImageFont.truetype("kumo.ttf", 28)
        #     draw.text([i * 24, 0], char, (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)),
        #               font=font)
        # img.save(f,'png')
        # data=f.getvalue()
        # code = ''.join(char_list)
        # request.session['code'] = code
        # return HttpResponse(data)
    
        #以上验证码代码太长,将内容封装到BBS目录下utils目录中
        from utils.random_check_code import random_check_code
        img,code=random_check_code()
        stream=BytesIO()
        img.save(stream,'png')
        request.session['code']=code
        return HttpResponse(stream.getvalue())
    view
    urlpatterns = [
        url(r'^login/', views.login),
        url(r'^check_code/', views.check_code),
    ]
    url
    import random
    from PIL import ImageDraw,ImageFont,Image,ImageFilter
    
    
    def random_check_code(width=120, height=30, char_length=5, font_file='kumo.ttf', font_size=28):
        code = []
        img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255))
        draw = ImageDraw.Draw(img, mode='RGB')
    
        def rndChar():
            """
            生成随机字母
            :return:
            """
            return chr(random.randint(65, 90))
    
        def rndColor():
            """
            生成随机颜色
            :return:
            """
            return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))
    
        # 写文字
        font = ImageFont.truetype(font_file, font_size)
        for i in range(char_length):
            char = rndChar()
            code.append(char)
            h = random.randint(0, 4)
            draw.text([i * width / char_length, h], char, font=font, fill=rndColor())
    
        # 写干扰点
        for i in range(40):
            draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
    
        # 写干扰圆圈
        for i in range(40):
            draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
            x = random.randint(0, width)
            y = random.randint(0, height)
            draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor())
    
        # 画干扰线
        for i in range(5):
            x1 = random.randint(0, width)
            y1 = random.randint(0, height)
            x2 = random.randint(0, width)
            y2 = random.randint(0, height)
            draw.line((x1, y1, x2, y2), fill=rndColor())
    
        img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) #加滤镜,可以增加颜色的不同
        return img, ''.join(code)
    utils/random_check_code.py
    !DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>$Title$</title>
        <link rel="stylesheet" href="/static/bootstrap-3.3.5-dist/css/bootstrap.css">
        <style>
            .login{
                margin: 0 auto;
                padding: 20px;
                margin-top: 150px;
                margin-left: 350px;
            }
        </style>
    </head>
    
    <body>
    
    <div class="login">
        <form class="form-horizontal" method="POST">
            {% csrf_token %}
    
        <div class="form-group">
            <label class="col-sm-2 control-label">用户名</label>
            <div class="col-sm-4">
                <input name="user" class="form-control" placeholder="用户名">
            </div>
        </div>
    
        <div class="form-group">
            <label class="col-sm-2 control-label">密码</label>
            <div class="col-sm-4">
                <input type="password"  name="pwd" class="form-control" placeholder="密码">
            </div>
        </div>
    
        <div class="form-group">
            <label class="col-sm-2 control-label">验证码</label>
            <div class="col-sm-2">
                <input class="form-control" placeholder="验证码" name="code">
            </div>
    
            <div class="col-sm-2">
                <img src="/check_code/" alt="" style=" 120px;height: 30px">
            </div>
        </div>
    
        <div class="form-group">
            <div class="col-sm-offset-2 col-sm-10">
                <button type="submit" class="btn btn-default">登录</button>
            </div>
        </div>
    
    </form>
    </div>
    
    </body>
    </html>
    login

    方法二:

    使用Form表单:

    #生成随机验证码
    from PIL import Image
    from io import BytesIO
    from PIL import ImageDraw,ImageFont
    def check_code(request):
    
        # #Django imag标签src属性导入图片的原理
        # f=open('static/imgs/1.jpg','rb')    #注意:static/imgs/1.jpg不能写成 /static/imgs/1.jpg
        # data=f.read()
        # f.close()
        # return HttpResponse(data)
        #创建code.png写入到本地BBS目录下
        # from PIL import Image
        # img=Image.new(mode='RGB',size=(120,30),color=(255,255,255)) #默认写入白板,随后在白板上写入字符串等
        # f=open('code.png','wb')
        # img.save(f,'png')   #png为图片后缀
        # f.close()
        # #将本地图片code.png读取到内存并使网页图片能显示出来
        # f=open('code.png','rb')
        # data=f.read()
        # f.close()
        # return HttpResponse(data)
        #以上操作比较麻烦,需要写入本地又读取到内存中
        #以下操作为在内存中开辟空间,在内存中进行读写等操作
        # from io import BytesIO
        # #写入内存中
        # f=BytesIO()
        # img=Image.new(mode='RGB',size=(120,30),color=(255,255,255))
        # img.save(f,'png')
        # #从内存中读出来
        # data=f.getvalue()
        # return HttpResponse(data)
    
        # from io import BytesIO
        # from PIL import ImageDraw,ImageFont
        f=BytesIO()
        img=Image.new(mode='RGB',size=(120,30),color=(255,255,255))
        draw=ImageDraw.Draw(img,mode='RGB')
        # draw.point([100, 25], fill="red")
        # draw.point([30, 20], fill=(187, 255, 255))
        # draw.line((10, 10, 20, 30), fill='red')
        # draw.line((100, 10, 30, 20), fill=(180, 255, 255))
        # draw.arc((30, 25, 80, 10), 0, 360, fill="red")
        # font = ImageFont.truetype("kumo.ttf", 28)
        # draw.text([0, 0], 'python', "red",font=font)
        import random
        # char_list=[]
        # for i in range(5):
        #     char=chr(random.randint(65,109))
        #     char_list.append(char)
        # ''.join(char_list)
        # #列表生成式,但是字母随机了,字体颜色不随机,所以不用列表生成式
        # v=''.join([ chr(random.randint(65,109)) for i in range(5)])
        # for i in range(5):
        #     char=chr(random.randint(65,109))
        #     font=ImageFont.truetype("kumo.ttf", 28)
        #     draw.text([i*24,0],char,(random.randint(0,255),random.randint(0,255),random.randint(0,255)),font=font)
        #写入的字符串需要自己知道内容,方便表单的校验
        # char_list = []
        # for i in range(5):
        #     char=chr(random.randint(65,109))
        #     char_list.append(char)
        #     font=ImageFont.truetype("kumo.ttf", 28)
        #     draw.text([i*24,0],char,(random.randint(0,255),random.randint(0,255),random.randint(0,255)),font=font)
        # code=''.join(char_list)
        #但又面临的问题是POST请求时提交数据,获取不到,所以需要写入session里,并进入login函数中增加POST请求
        # char_list = []
        # for i in range(5):
        #     char = chr(random.randint(65, 109))
        #     char_list.append(char)
        #     font = ImageFont.truetype("kumo.ttf", 28)
        #     draw.text([i * 24, 0], char, (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)),
        #               font=font)
        # img.save(f,'png')
        # data=f.getvalue()
        # code = ''.join(char_list)
        # request.session['code'] = code
        # return HttpResponse(data)
    
        #以上验证码代码太长,将内容封装到BBS目录下utils目录中
        from utils.random_check_code import random_check_code
        img,code=random_check_code()
        stream=BytesIO()
        img.save(stream,'png')
        request.session['code']=code
        return HttpResponse(stream.getvalue())
    
    
    
    
    
    
    #登录页面,使用Form表单
    #生成Form表单
    from django.forms import Form
    from django.forms import widgets
    from django.forms import fields
    
    class LoginForm(Form):
        user = fields.CharField(
            widget=widgets.TextInput(attrs={'class':"form-control",'placeholder':'用户名'}),
            label="用户名",
            required=True,
            max_length=8,
            min_length=2,
            error_messages={
                'required':'用户名不能为空',
                'min_length':'用户名不得少于2个字符',
                'max_length':'用户名不得多于8个'
            }
        )
    
        pwd = fields.CharField(
            widget=widgets.TextInput(attrs={'class':"form-control",'placeholder':'密码','type':'password'}),
            label="密码",
            required=True,
            max_length=10,
            min_length=2,
            error_messages={
                'required': '密码不能为空',
                'min_length': '密码不得少于2个字符',
                'max_length': '密码不得多于10个'
            }
        )
    
        code=fields.CharField(
            widget=widgets.TextInput(attrs={'class':"form-control",'placeholder':'验证码'}),
            label="验证码",
            required=True,
            error_messages={
                'required':'验证码不能为空'
            }
        )
    
    
    
    
    
    def login_form(request):
        if request.method=='GET':
            obj = LoginForm()
            return render(request, 'login_form.html', {'obj': obj})
        else:
            obj=LoginForm(request.POST)
            if obj.is_valid():
                input_user=obj.cleaned_data['user']
                input_pwd=obj.cleaned_data['pwd']
                input_code =obj.cleaned_data['code']
                session_code=request.session.get('code')
    
                if models.UserInfo.objects.filter(username=input_user,password=input_pwd).first():
                    if input_code.upper()==session_code.upper():
                        return render(request,'information.html')
                    else:
                        return render(request, 'login_form.html', {'obj': obj, 'msg': '验证码错误'})
                return render(request, 'login_form.html',{'obj':obj,'msg':'用户名或密码错误'})
            else:
                v=obj.errors
                print(v)
                return render(request,'login_form.html',{'obj':obj})
    
    views
    views
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>$Title$</title>
        <link rel="stylesheet" href="/static/bootstrap-3.3.5-dist/css/bootstrap.css">
        <style>
            .login{
                margin: 0 auto;
                padding: 20px;
                margin-top: 150px;
                margin-left: 350px;
            }
    
    
        </style>
    </head>
    
    <body>
    
    <div class="login">
        <form class="form-horizontal" method="POST" novalidate>
        {% csrf_token %}
        <div class="form-group">
            <label class="col-sm-2 control-label">{{ obj.user.label }}</label>
            <div class="col-sm-4">
                {{ obj.user }}{{ obj.errors.user.0 }}
            </div>
        </div>
    
        <div class="form-group">
            <label class="col-sm-2 control-label">密码</label>
            <div class="col-sm-4">
                {{ obj.pwd }}{{ obj.errors.pwd.0 }}
            </div>
        </div>
    
        <div class="form-group">
            <label class="col-sm-2 control-label">验证码</label>
            <div class="col-sm-2">
                {{ obj.code }}{{ obj.errors.code.0 }}{{ msg }}
            </div>
    
            <div class="col-sm-2">
                <img src="/check_code/" alt="" style=" 120px;height: 30px">
            </div>
        </div>
    
        <div class="form-group">
            <div class="col-sm-offset-2 col-sm-10">
                <button type="submit" class="btn btn-default">登录</button>
            </div>
        </div>
    
    </form>
    </div>
    
    </body>
    </html>
    
    login_form
    login_form
    rlpatterns = [
    
        url(r'^check_code/', views.check_code),
    
        url(r'^login_form/', views.login_form),
    
    ]
    url
    import random
    from PIL import ImageDraw,ImageFont,Image,ImageFilter
    
    
    def random_check_code(width=120, height=30, char_length=5, font_file='kumo.ttf', font_size=28):
        code = []
        img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255))
        draw = ImageDraw.Draw(img, mode='RGB')
    
        def rndChar():
            """
            生成随机字母
            :return:
            """
            return chr(random.randint(65, 90))
    
        def rndColor():
            """
            生成随机颜色
            :return:
            """
            return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))
    
        # 写文字
        font = ImageFont.truetype(font_file, font_size)
        for i in range(char_length):
            char = rndChar()
            code.append(char)
            h = random.randint(0, 4)
            draw.text([i * width / char_length, h], char, font=font, fill=rndColor())
    
        # 写干扰点
        for i in range(10):
            draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
    
        # 写干扰圆圈
        for i in range(10):
            draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
            x = random.randint(0, width)
            y = random.randint(0, height)
            draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor())
    
        # 画干扰线
        for i in range(2):
            x1 = random.randint(0, width)
            y1 = random.randint(0, height)
            x2 = random.randint(0, width)
            y2 = random.randint(0, height)
            draw.line((x1, y1, x2, y2), fill=rndColor())
    
        img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) #加滤镜,可以增加颜色的不同
        return img, ''.join(code)
    utils/random_check_code.py
  • 相关阅读:
    nsq main里面golang多个协程管理写法
    关于centos压测的问题
    Jaeger全链路go实现,包含http和消息队列的链式传递
    mstsc远程报:这可能是由于CredSSP 加密Oracle修正的两种完美解决方法
    Axure9:一键复制Iconfont图标到Axure的插件安装
    Axure9:导入阿里云DataV.GeoAtlas矢量地图到Axure
    Axure:编辑技巧:拖动复制、编组、组内选中、穿透选中、选中模式
    Axure学习一:打开软件,预览和生成HTML原型、安装Chrome插件
    Axure RP授权码
    vm 安装rethat和centos
  • 原文地址:https://www.cnblogs.com/wu-chao/p/8661953.html
Copyright © 2011-2022 走看看