Майним крипто-коины с помощью Python и компьютерного зрения
После внезапного обогащения энтузиастов, которые поиграли в начале года в приложение Notcoin в телеграм, подобные проекты стали расти как грибы. Да и грибников заметно поприбавилось. Но в данной статье мы не будем касаться тем блокчейна или финансов, а рассмотрим простой пример применения компьютерного зрения для фарма поинтов в самом популярном, после Notcoin, проекте — хомяке комбате. Название явно на что-то намекает, но да ладно.
Это не первый проект, который я автоматизирую, и не самый нуждающийся в этом. Да и без компьютерного зрения с автоматизацией хомяка можно спокойно обойтись. Но с ним, во-первых, интереснее, а во-вторых — это просто хороший пример с минимумом строк кода для демонстрации возможностей библиотеки cv2. Статья, соответственно, предназначена для энтузиастов и начинающих специалистов.
Начнем с того, что мы установим все необходимые зависимости и импортируем их в свой проект. Вот они, слева направо.
import pyautogui
import keyboard
import cv2
import numpy as np
import time
С помощью pyautogui наш бот будет управлять мышью. Keyboard пригодится для назначения горячих клавиш, чтобы управлять работой бота. cv2 наградит бота зрением, пусть и компьютерным, с помощью которого тот будет находить совпадения с искомым изображением. А numpy пригодится для работы с большими массивами, но тут он почти для галочки, не бойтесь. Модуль time тоже понадобится, чтобы ставить таймауты в работе программы.
Далее напишем небольшую конструкцию- переключатель.
def change():
global work
work = not work
work = False
Функция change при вызове всего лишь меняет значение переменной work, которая будет использована в бесконечном цикле. И если work будет False, работа нашего кода будет останавливаться. И наоборот запускаться, в противоположном случае.
Кстати, забыл упомянуть, что разработчики проекта, над которым мы сейчас проводим эксперимент, большие молодцы, и убрали возможность пользоваться приложением на десктопных устройствах. Поэтому для его запуска понадобится эмулятор Android.
Теперь определим основную логику работы бота:
Он ищет совпадение с изображением полностью заполненной энергии.
Если находит совпадение, ищет изображение монеты и кликает на неё энное количество раз.
И всё это работает в бесконечном цикле.
Значит со скриншота приложения необходимо вырезать две области, которые помечены красным, и разместить их в отдельные файлы, конечно же.
Теперь напишем функцию для кликов по монетке. Она будет принимать путь к исходному изображению, а так же порог чувствительности для компьютерного зрения и интервал (таймаут) в секундах.
def click(template_path, threshold=0.8, interval=0.0001):
template = cv2.imread(template_path, 0)
w, h = template.shape[::-1]
screenshot = pyautogui.screenshot()
screenshot = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)
# Переводим скриншот в оттенки серого.
gray_screenshot = cv2.cvtColor(screenshot, cv2.COLOR_BGR2GRAY)
# Находим изображение на экране.
result = cv2.matchTemplate(gray_screenshot, template, cv2.TM_CCOEFF_NORMED)
loc = np.where(result >= threshold)
# Кликаем по найденным координатам.
for pt in zip(*loc[::-1]):
center_x = pt[0] + w // 2
center_y = pt[1] + h // 2
for _ in range(260):
pyautogui.doubleClick(center_x, center_y)
break
Переменной template будет присвоено исходное изображение монетки, но в оттенках серого, так как мы указали в параметрах 0. Это необходимость, так как в оттенках серого компьютер зрит лучше. Сразу вычисляем высоту и ширину исходника, и присваиваем переменным. А далее по ходу исполнения кода он делает скриншот, сравнивает с исходником, получает координаты области с совпадением, и делает 260 даблкликов по ней. Координаты я ищу немного кривовато и в итоге loc содержит большой массив, из которого я использую лишь самые первые координаты, после чего цикл прерываю. Но лучше сделать не смог, извините.
А теперь напишем аналогичную функцию, но с задачей искать совпадение с картинкой полной энергии, после чего вызывать функцию click.
def find(template_path, threshold=0.9, interval=1):
keyboard.add_hotkey('`', change)
# Загружаем изображение, которое мы хотим найти на экране. 0- в градациях серого.
template = cv2.imread(template_path, 0)
w, h = template.shape[::-1]
try:
while True:
if work:
# Получаем скриншот экрана.
screenshot = pyautogui.screenshot()
screenshot = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)
# Переводим скриншот в оттенки серого.
gray_screenshot = cv2.cvtColor(screenshot, cv2.COLOR_BGR2GRAY)
# Находим изображение на экране.
result = cv2.matchTemplate(gray_screenshot, template, cv2.TM_CCOEFF_NORMED)
loc = np.where(result >= threshold)
for _ in zip(*loc[::-1]):
click('coin.bmp')
break
time.sleep(interval)
except KeyboardInterrupt:
print('\nВыход из программы')
В целом всё аналогично. Добавил лишь ожидание горячей клавиши, чтобы можно было остановить программу в любое время нажатием на тильду (Ё). Ну и для красоты заключил в try-except.
И это всё. Пишем последние строки и запускаем скрипт (не забыв нажать на Ё для запуска логики в цикле).
if __name__ == "__main__":
find('energy.bmp')
По сути, этот код многофункционален, и его без труда, с минимальными изменениями, можно переделать под любые другие задачи. На всякий случай оставлю и полную версию кода:
import pyautogui
import keyboard
import cv2
import numpy as np
import time
def change():
global work
work = not work
work = False
def find(template_path, threshold=0.9, interval=1):
keyboard.add_hotkey('`', change)
# Загружаем изображение, которое мы хотим найти на экране. 0- в градациях серого.
template = cv2.imread(template_path, 0)
w, h = template.shape[::-1]
try:
while True:
if work:
# Получаем скриншот экрана.
screenshot = pyautogui.screenshot()
screenshot = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)
# Переводим скриншот в оттенки серого.
gray_screenshot = cv2.cvtColor(screenshot, cv2.COLOR_BGR2GRAY)
# Находим изображение на экране.
result = cv2.matchTemplate(gray_screenshot, template, cv2.TM_CCOEFF_NORMED)
loc = np.where(result >= threshold)
for _ in zip(*loc[::-1]):
click('coin.bmp')
break
time.sleep(interval)
except KeyboardInterrupt:
print('\nВыход из программы')
def click(template_path, threshold=0.8, interval=0.0001):
template = cv2.imread(template_path, 0)
w, h = template.shape[::-1]
screenshot = pyautogui.screenshot()
screenshot = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)
# Переводим скриншот в оттенки серого.
gray_screenshot = cv2.cvtColor(screenshot, cv2.COLOR_BGR2GRAY)
# Находим изображение на экране.
result = cv2.matchTemplate(gray_screenshot, template, cv2.TM_CCOEFF_NORMED)
loc = np.where(result >= threshold)
# Кликаем по найденным координатам.
for pt in zip(*loc[::-1]):
center_x = pt[0] + w // 2
center_y = pt[1] + h // 2
for _ in range(260):
pyautogui.doubleClick(center_x, center_y)
break
if __name__ == "__main__":
find('energy.bmp')
Не судите меня строго по этому скрипту, большую часть жизни я вообще бегал с пистолетиком, и пристрастился к разработке сравнительно недавно, поэтому всего лишь юный падаван в возрасте. Хотя могу писать и большие скучные штуки, но вот писать о них получится дольше, чем сам код. А если будут вопросы- добро пожаловать в телеграм. У меня там небольшой клуб по интересам.