Как сделать капчу для телеграмм бота?
Нужно, чтобы при команде старт, прежде всех функций пользователь прошел капчу. Как это реализовать в пайтоне?
Ответы (3 шт):
Попробуйте библиотеку pyTelegramBotCAPTCHA. На странице проекта достаточно подробно описаны примеры внедрения капчи.
А лучше самому сделать используя вот это
from captcha.image import ImageCaptcha
Вообще, если картинкой, то можно сделать капчу через библиотеку Pillow и функции для генерации текста с заданными параметрами, после чего делать в Pillow картинку с созданными текстом, а возвращать сгенерированный текст плюс картинку, и уже в нужном месте, при вызове команды там /start, вызывать функцию.
Вообще мой совет - использовать aiogram, так как там для такого есть машина состояний, а есть ли она в других библиотеках - я не знаю.
Пример кода генерации каптчи:
from PIL import Image, ImageDraw, ImageFont
import random
import string
from io import BytesIO
def generate_captcha():
text = ''.join(random.choices(string.ascii_uppercase + string.digits, k=9))
image = Image.new('RGB', (960, 540), color=(144, 164, 135))
draw = ImageDraw.Draw(image)
font = ImageFont.truetype('font.ttf', 150)
colors = [
(255, 255, 2555),
(216, 151, 151),
(199, 151, 216),
(132, 255, 233),
(0, 0, 0),
(243, 255, 109),
(108, 141, 255),
(134, 134, 134),
(0, 80, 98)
]
total_text_width = sum(draw.textbbox((0, 0), char, font=font)[2] for char in text) + (len(text) - 1) * 5
y = 213
x = (960 - total_text_width) // 2
for i, char in enumerate(text):
color = colors[i % len(colors)]
draw.text((x, y), char, font=font, fill=color)
bbox = draw.textbbox((0, 0), char, font=font)
char_width = bbox[2] - bbox[0]
x += char_width + 5
byte = BytesIO()
image.save(byte, 'PNG')
byte.seek(0)
byte_data = byte.getvalue()
print(byte_data)
return text, byte_data
Пример для реализации капчи в боте:
@router.message(Command("start"))
async def start(message: Message, command: CommandObject, state: FSMContext) -> None:
"""
Handle the /start commands for new users.
:param message: The incoming message object.
:param command: he parsed commands object.
:param state: FSMContext object.
:return: None
"""
check = await check_users_subscription(message.bot, message.from_user.id)
if check is True:
invite_link = await create_invite_link(message, message.from_user.id)
username = message.from_user.username
if username is None:
username = message.from_user.first_name
kb = ReplyKeyboardBuilder()
member = await database.check_user(message.from_user.id)
if int(message.from_user.id) in data["ADMIN_LIST"]:
button = KeyboardButton(text="Список пользователей с 20+ реф")
button2 = KeyboardButton(text="Список пользователей 5-20 реф")
kb.row(button).row(button2)
text, image = generate_captcha()
if command.args:
check_user = await database.check_user(message.from_user.id)
if check_user is False:
ref_id = int(await decode_invite_link(command.args))
await state.update_data(link=ref_id)
await state.update_data(capcha=text)
await state.update_data(username=username)
await message.answer_photo(
photo=BufferedInputFile(image, filename="capcha"),
caption="Введите капчу с картинки"
)
await state.set_state(CHECKCAPCHA.capcha)
elif member is False:
await state.update_data(username=username)
await state.update_data(kb=kb)
await state.update_data(capcha=text)
await message.answer_photo(
photo=BufferedInputFile(image, filename="capcha"),
caption="Введите капчу с картинки"
)
await state.set_state(CHECKCAPCHA.nocp)
if member is True:
await database.add_user(message.from_user.id, username)
username, ref_count = await database.get_user_info(message.from_user.id)
but = KeyboardButton(text="Подключить крипто кошелек")
kb.row(but)
keyb = ReplyKeyboardMarkup(resize_keyboard=True, keyboard=kb.export())
await message.answer_photo(
caption=dedent(f"""
?<b>{message.from_user.mention_html(username)}</b>, добро пожаловать в нашего бота ?
На данный момент вами приглашено: <code>{ref_count} / 20</code> человек(а) ?
? Ваша реферальная ссылка:
<code>{invite_link} </code>
"""),
photo=FSInputFile("images/image.jpg"),
reply_markup=keyb
)
else:
await message.answer("Вы не подписаны на канал, подпишитесь и перейдите еще раз по спец. ссылке")
Это лишь пример моего решения, я не призываю никого его использовать.