CAPTCHA
используется любым веб-сайтом, который хочет ограничить использование ботами. В репозиториях Python есть модуль captcha
, который может генерировать капчи, а встроить его во Flask не составит труда. Так же есть много других вариантов.
Возникает справедливый вопрос: - зачем изобретать велосипед? Есть несколько вариантов ответов:
captcha
легко распознаются. Да и другие открытые технологии тоже.captcha
тащит за собой много дополнительных модулей).AJAX
, то вообще сходят с ума. Для тестового приложения с пользовательской капчей создадим следующую структуру:
/test_app test.py /templates capcha.html
Создадим нужные директории и пустые файлы командами bash
:
# создаем директории $ mkdir -p test_app/templates # создаем пустые файлы $ touch test_app/test.py test_app/templates/capcha.html
Готово. После этого можно открыть созданные пустые файлы и скопировать туда соответствующий код, представленный ниже. Весь представленный код хорошо прокомментирован, так что разобраться будет несложно.
Пользовательская капча генерируется модулем
Pillow
, следовательно необходимо установить модульPillow
в виртуальное окружение, в котором установленFlask
.
Как запускать? Активируем виртуальное окружение с установленными Flask
и Pillow
. Далее, если ранее директорий test_app
создавался в корне, то просто нужно перейти в папку test_app
и запустить приложение.
# активируем виртуальное окружение $ source .venv/bin/activate # переходим в папку с приложением $ cd test_app # экспортируем приложение $ export FLASK_APP=test # запускаем приложение $ flask run # * Serving Flask app 'test' # * Debug mode: off # * Running on http://127.0.0.1:5000 # Press CTRL+C to quit
Далее переходим по ссылке http://127.0.0.1:5000 и тестируем...
Пользовательскую капчу будем генерировать при помощи стороннего модуля Pillow
, следовательно необходимо установить его в виртуальное окружение, в котором установлен Flask
.
Весь представленный код хорошо прокомментирован, так что разобраться будет несложно. С подмодулем
ImageDraw
модуляPillow
, при помощи которого генерируется картинка можно ознакомиться в материале "Подмодуль ImageDraw модуля Pillow в Python"
# файл test_app/test.py from flask import (Flask, render_template, request, session, url_for, redirect) from PIL import Image, ImageDraw, ImageFont from random import choice, randint from io import BytesIO from os import urandom # объект приложения app = Flask(__name__) # создадим ключ для сессий app.secret_key = urandom(24) # главная страница с капчей @app.route("/", methods=['POST', 'GET']) def start(): error = False if request.method == "POST": # получаем данные формы input_captcha = request.values.get('input_captcha') # получаем данные сессии sess_captcha = session.get('code') # сравниваем данные сессии и формы if str(input_captcha).lower() == str(sess_captcha).lower(): # при успехе перенаправляем на # страничку приветствия return redirect(url_for('hello')) else: # при неправильном вводе кода # капчи - показываем надпись error = True return render_template('capcha.html', error=error) # генерация собственной капчи при помощи `Pillow` @app.route('/captcha.png', methods=['GET']) def captcha(width=200, height=100): # символы для капчи выбираем с таким расчетом, # что бы посетители их не спутали с похожими # например букву `l` и цифру `1` легко спутать # генерация кода капчи из 5 символов code = ''.join([choice('QERTYUPLKJHGFDSAZXCVBN23456789') for i in range(5)]) # сгенерированный код пишем в сессию session['code'] = code # создаем подложку img = Image.new('RGB', (width,height), (255,255,255)) # получаем контекст рисования draw = ImageDraw.Draw(img) # Подключаем растровый шрифт (укажите свой) font = ImageFont.truetype('/usr/share/fonts/truetype/freefont/FreeSans.ttf', size=50) # начальное положение символов кода x=0; y=12; # наносим код капчи for let in code: if x == 0: x = 5 else: x = x + width/5 # случайное положение по высоте y = randint(3,55) # наносим символ draw.text((x,y), let, font=font, fill=(randint(0,200), randint(0,200), randint(0,200), 128)) # создаем шум капчи (в данном случае черточки) # можно создать шум точками (кому как нравиться) for i in range(40): draw.line([(randint(0,width),randint(0,height)), (randint(0,width),randint(0,height))], randint(0, 200), 2, 128) # создаем объект в буфере f = BytesIO() # сохраняем капчу в буфер img.save(f, "PNG") # возвращаем капчу как байтовый объект return f.getvalue() # Станица откроется при # правильном вводе капчи @app.route('/ok') def hello(): return '<h1 style="text-align:center;margin-top:150px;">Привет!</h1>' if __name__ == "__main__": app.run(debug=True)
<!-- файл test_app/templates/capcha.html --> <html> <head> <meta charset="utf-8"> <style> html,body {height:100%;width:100%;margin:0;} body {display:flex;} form {margin:auto;} #error{color:red;} #captcha{width:200px;} input{width:200px;font-size:150%;margin-top:15px;} </style> </head> <body> <form id="form" method="POST"> <h3 id="h3">Кликните по картинке для смены изображения.</h3> <!-- При вводе неправильного кода будет появляться надпись --> {% if error %} <h3 id="error">НЕПРАВИЛЬНЫЙ ВВОД!</h3> {% endif %} <!-- сгенерированную капчу подключим как простую картинку --> <!-- так как маршрут определен как route('/captcha.png'...) --> <div id="captcha"><img src="/captcha.png"></div> <!-- поле ввода кода с картинки --> <input name="input_captcha" type="text" placeholder="Буквы и цифры"> <br> <input type="submit" value="Проверить"> </form> <!-- сделаем так, чтобы рисунок капчи обновлялся при клике на нее. --> <!-- Для этого подключим jquery по ссылке CDN --> <script src="https://code.jquery.com/jquery-3.6.3.min.js" integrity="sha256-pvPw+upLPUjgMXY0G+8O0xUf+/Im1MZjXxxgOcBQBXU=" crossorigin="anonymous"></script> <!-- обновлять картинку будем AJAX-ом --> <script> function reCaptcha() { $.ajax({ type: 'GET', url: '/captcha.png', success: function(data){ $('#captcha').html('<img src="/captcha.png">'); } }); } $(document).ready(function() { // По клику на картинке обновляем последнюю $('#captcha').click(function(){ reCaptcha(); }); }); </script> </body> </html>