Многие помнят проект place, запущенный однажды на Reddit. Я решил попробовать создать бота в Телеграме с точно такой же функцией.
304 открытий2К показов
Многие помнят проект place, запущенный однажды на Reddit и собравший вокруг себя немало поклонников. Суть предельно проста: раз в пять минут можно закрасить один пиксель на поле 1000×1000 пикселей в свой цвет. Я решил попробовать создать бота в телеграмм с точно такой же функцией, а также что-нибудь порисовать…
Вступление
Статья носит познавательно-обучающий характер, и вот то, что можно из неё извлечь:
Библиотека telebot даёт возможность создания телеграм бота а также отслеживания команд с использованием @bot.message_handler(commands=[]) и текста с использованием @bot.message_handler(content_types=[‘text’]).
Библиотека telebot даёт возможность отправки сообщений с использованием bot.send_message(message.chat.id, text = «») и фото с помощью bot.send_photo(message.chat.id, img).
Библиотека pickle позволяет просто сохранять данные в файле с помощью pickle.dump() и извлекать оттуда используя pickle.load().
С помощью pillow можно создавать изображения используя Image.new() и изменять цвет отдельных пикселей используя img.putpixel().
Как писать текст с помощью PyAutoGUI.
Статья также позволяет изучить работу time.time() и создание простого таймера с её использованием.
Код бота
Для бота я буду использовать библиотеки (некоторые из них необходимо установить через pip install)(telebot, pillow):
import telebot # для бота
import pickle # для открытия файла с цветами поля
from pathlib import Path # для удаления неугодного файла
from PIL import Image # для отправки холста пользователю
import time # для высчитывания времени межу изменениями цвета
Зададим значение переменных:
st = time.time() - 100 # переменная измерения времени и его ограничения
l = 100 # ширина и высота поля
h = 7 # размер пикселя на изображении
Запишем в data данные из файла, который мы потом создадим (содержит цвета пикселей):
data = []
try:
with open("data.pickle", "rb") as f:
data = pickle.load(f)
except Exception as ex:
print("Error during unpickling object (Possibly unsupported):", ex)
Теперь сделаем объяснение работы бота и отправку текущего изображения поля по команде start:
@bot.message_handler(commands=['start']) # отслеживание команды
def start(message):
# пояснения:
bot.send_message(message.chat.id, text="Вы находитесь в боте для группового рисования картины. В этом боте вы можете внести свой вклад в сетевой холст, на котором рисуют и другие люди. Вы можете изменить цвет одного из пикселей раз в 10 секунд. Так вы можете рисовать свои шедеврыы, но учтите, что их могут изменять другие люди.")
bot.send_message(message.chat.id, text = "Чтобы провести все вышеописанные операции, необходимо отправить мне цвет пикселя в формате: x, y, красный, зелёный, синий (через запятую, без пробелов). Причём ширина поля 0-99, длина 0-99, максимальное значение каждого из цветов 255, минимальное 0. Например:")
bot.send_message(message.chat.id, text = "0,0,255,255,255")
bot.send_message(message.chat.id, text = "Отправь 'к' чтобы увидеть полученное изображение.")
# берём данные из файла
try:
with open("data.pickle", "rb") as f:
data = pickle.load(f)
except Exception as ex:
print("Error during unpickling object (Possibly unsupported):", ex)
# создаём изображение с pillow
img = Image.new("RGB", (l*h, l*h), 'black')
for i in range(l): # для каждого пикселя поля
for j in range(l):
# если data[i*l + j] является не нулём
try:
# рисуем квадрат hхh
for i1 in range(h):
for j1 in range(h):
img.putpixel((i*h +i1, j*h +j1), tuple(data[i*l + j]))
# иначе ничего не делаем (имитация бурной деятельности):
except TypeError:
if j // 2000 == 3:
print("0")
bot.send_photo(message.chat.id, img) # отправляем полученное изображение
Далее отслеживаем любой текст от пользователя и в случае необходимости отправляем картинку:
@bot.message_handler(content_types=['text']) # отслеживаем текст
def func(message):
# если пользователь просит изображение поля
if message.text == "к" or message.text == "k" or message.text == "К":
# берём данные из файла (обновляем)
try:
with open("data.pickle", "rb") as f:
data = pickle.load(f)
except Exception as ex:
print("Error during unpickling object (Possibly unsupported):", ex)
# создаём изображение с pillow
img = Image.new("RGB", (l*h, l*h), 'black')
for i in range(l): # для каждого пикселя поля
for j in range(l):
# если data[i*l + j] является не нулём (изменялся хоть раз)
try:
# рисуем квадрат hхh
for i1 in range(h):
for j1 in range(h):
img.putpixel((i*h +i1, j*h +j1), tuple(data[i*l + j]))
# иначе ничего не делаем (имитация бурной деятельности):
except TypeError:
if j // 2000 == 3:
print("0")
bot.send_photo(message.chat.id, img) # отправляем полученное изображение
Если пользователь отправил сообщение не меньше минимальной длины запроса на рисование (минимальный — 0,0,0,0,0 — длина 9), проверяем на ошибки:
else:
# если длиннее минимального
if len(message.text) >= 9:
# переменная таймера - глобальная
global st
# Если с прошлого изменения пикселя прошло не меньше 20 секунд
if time.time() - st < 20:
bot.send_message(message.chat.id, text = "слишком часто. Промежуток между сообщениями - 20 секунд")
else:
# преобразуем текст сообщения в массив с координатами и цветом
t = message.text
x = []
n = ""
# с учётом разделителей
for i in t:
if i != ",":
n += i
else:
x.append(n)
n = ""
x.append(n)
n = ""
# просматриваем корректность цветов и координат:
# не вышли ли за край поля, и т.п.
a = 0
n = 0
# в случае нарушений n = 1 (флаг)
while a <= len(x)-1:
try:
x[a] = int(x[a])
if a < 2:
if x[a] > l:
n = 1
else:
if x[a] > 255 or x[a] < 0:
n = 1
except Exception:
n = 1
a += 1
Если не нашли ошибку — отслеживаем координаты рисования и красим пиксель в необходимый цвет, оповещаем пользователя, обновляем таймер:
import pickle
# создаём массив
data = []
data = [0] * (100 * 100)
# сохраняем
try:
with open("data.pickle", "wb") as f:
pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL)
except Exception as ex:
print("Error during pickling object (Possibly unsupported):", ex)
Не забудем создать «data.pickle» с помощью другого кода. Он нужен единожды и запускается первым. Указываем размер поля и сохраняем (после тот же размер нужно указать в программе бота):
import pickle
# создаём массив
data = []
data = [0] * (100 * 100)
# сохраняем
try:
with open("data.pickle", "wb") as f:
pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL)
except Exception as ex:
print("Error during pickling object (Possibly unsupported):", ex)
Далее запускаем хостинг бота на pythonAnywhere (инструкция). Не забудьте установить необходимые библиотеки. Это делается с помощью обычного pip install в консоли на сайте (в инструкции описана установка библиотеки telebot, вам нужна ещё pillow (pip install pillow))
Бот успешно работает, вы можете опробовать его в телеграмме по ссылке.
Автоматизация
После написания основного кода я решил автоматизировать скорее не запросы, а преобразование картинки в запросы.
Начнём с импорта библиотеки pillow и создания текстового файла с координатами:
from PIL import Image
f = open("result.txt", "w+")
Далее откроем изображение (лучше пиксельарт) и спросим у пользователя координаты размещения:
img = Image.open('img.jpg')
print("X:")
x = int(input())
print("Y:")
y = int(input())
Для каждого пикселя изображения нужно узнать его будущее местоположение и цвет:
data = []
for i in range(img.size[0]):
for j in range(img.size[1]):
col = img.getpixel((i, j))
data.append(str(i+x) + "," + str(j+y) + "," + str(col[0]) + "," + str(col[1]) + "," + str(col[2]))
Записываем полученные координаты в файл:
for i in data:
f.write(i + "\n")
f.close()
Всё! После запуска получаем то, что необходимо отправлять боту.
Автоматизация отправки
Так как цель тут — скорее изучение Python, то почему бы не использовать библиотеку pyautoGUI (pip install PyAutoGUI)?
Благо, нам необходимо только вписать текст и нажать Enter:
import pyautogui
from time import sleep
# открываем файл с координатами
f = open("result.txt")
# читаем его
data = f.readlines()
# убираем переходы на следущую строку
diction = []
for i in data:
a = str(i)
diction.append(a[0:len(i)-1])
# вписываем запрос в телеграм и отправляем боту
for i in diction:
sleep(22)
pyautogui.typewrite(i, interval=0.0)
pyautogui.press('enter')
После запуска вышеописанного кода в течение 22 секунд необходимо перейти на вкладку telegram с открытым чатом бота и кликнуть в поле ввода сообщения.
Французские и эмиратские спецслужбы взломали iPhone Павла Дурова в 2017 году, используя уязвимости нулевого дня, якобы в рамках борьбы с терроризмом. После его ареста в 2024 году следствие предъявило Дурову серьёзные обвинения, включая использование Telegram в преступных целях
Расскажем о том, как правильно форматировать код и текст через Markdown в Telegram. Это удобный способ делиться технической информацией через мессенджер
Пользователи Telegram из России столкнулись с настойчивыми попытками мошенников украсть их аккаунты. Делается это через схему с участием в голосованиях.