First Commit
This commit is contained in:
@@ -0,0 +1,182 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Sistema de cliques automáticos baseado em reconhecimento de imagem.
|
||||
Clique no botão especificado por 'botaoparaclicar.png' a cada X segundos,
|
||||
apenas dentro do horário configurado no .env.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import random
|
||||
import cv2
|
||||
import numpy as np
|
||||
import pyautogui
|
||||
from datetime import datetime
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Carrega variáveis do .env
|
||||
load_dotenv()
|
||||
|
||||
INTERVALO_MINIMO_CLIQUE = int(os.getenv("INTERVALO_MINIMO_CLIQUE", "10"))
|
||||
INTERVALO_MAXIMO_CLIQUE = int(os.getenv("INTERVALO_MAXIMO_CLIQUE", "30"))
|
||||
INTERVALO_PRIMEIRO_CLIQUE = int(os.getenv("INTERVALO_PRIMEIRO_CLIQUE", "10"))
|
||||
MAXIMO_CLIQUES_POR_SESSAO = int(os.getenv("MAXIMO_CLIQUES_POR_SESSAO", "20"))
|
||||
INTERVALO_ENTRE_SESSOES = int(os.getenv("INTERVALO_ENTRE_SESSOES", "60"))
|
||||
MAXIMO_FALHAS = int(os.getenv("MAXIMO_FALHAS", "5"))
|
||||
HORA_INICIO = os.getenv("HORA_INICIO", "09:00")
|
||||
HORA_FIM = os.getenv("HORA_FIM", "18:00")
|
||||
CONFIANCA = float(os.getenv("CONFIANCA", "0.8"))
|
||||
IMAGEM_BOTAO = os.path.join(os.path.dirname(os.path.abspath(__file__)), "botaoparaclicar.png")
|
||||
LOG_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "log.txt")
|
||||
|
||||
pyautogui.FAILSAFE = True
|
||||
|
||||
|
||||
def gerar_intervalo_aleatorio(intervalo_min: int, intervalo_max: int) -> int:
|
||||
"""Gera um valor aleatório entre intervalo_min e intervalo_max (inclusive)."""
|
||||
return random.randint(intervalo_min, intervalo_max)
|
||||
|
||||
|
||||
def log(mensagem: str) -> None:
|
||||
"""Registra mensagem com timestamp."""
|
||||
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
linha = f"[{timestamp}] {mensagem}"
|
||||
print(linha)
|
||||
try:
|
||||
with open(LOG_FILE, "a", encoding="utf-8") as f:
|
||||
f.write(linha + "\n")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def dentro_horario(hora_inicio: str, hora_fim: str) -> bool:
|
||||
"""Verifica se o horário atual está dentro do intervalo configurado."""
|
||||
agora = datetime.now().time()
|
||||
hi = datetime.strptime(hora_inicio, "%H:%M").time()
|
||||
hf = datetime.strptime(hora_fim, "%H:%M").time()
|
||||
return hi <= agora <= hf
|
||||
|
||||
|
||||
def encontrar_botao(imagem_path: str, confianca: float = 0.8):
|
||||
"""
|
||||
Procura a imagem do botão na tela usando template matching.
|
||||
Retorna as coordenadas (x, y) do centro do botão ou None.
|
||||
"""
|
||||
if not os.path.isfile(imagem_path):
|
||||
log(f"ERRO: Imagem '{imagem_path}' não encontrada.")
|
||||
return None
|
||||
|
||||
# Captura screenshot da tela
|
||||
screenshot = pyautogui.screenshot()
|
||||
screenshot_np = np.array(screenshot)
|
||||
screenshot_cv = cv2.cvtColor(screenshot_np, cv2.COLOR_RGB2BGR)
|
||||
|
||||
# Carrega template do botão
|
||||
template = cv2.imread(imagem_path, cv2.IMREAD_UNCHANGED)
|
||||
if template is None:
|
||||
log(f"ERRO: Não foi possível carregar a imagem '{imagem_path}'.")
|
||||
return None
|
||||
|
||||
# Converte template para BGR se tiver alpha channel
|
||||
if template.shape[2] == 4:
|
||||
template_bgr = cv2.cvtColor(template, cv2.COLOR_BGRA2BGR)
|
||||
# Cria máscara para o canal alpha
|
||||
alpha = template[:, :, 3]
|
||||
mascara = alpha.astype(np.uint8)
|
||||
else:
|
||||
template_bgr = template
|
||||
mascara = None
|
||||
|
||||
# Template matching
|
||||
resultado = cv2.matchTemplate(screenshot_cv, template_bgr, cv2.TM_CCOEFF_NORMED, mask=mascara)
|
||||
_, max_val, _, max_loc = cv2.minMaxLoc(resultado)
|
||||
|
||||
if max_val >= confianca:
|
||||
h, w = template_bgr.shape[:2]
|
||||
centro_x = max_loc[0] + w // 2
|
||||
centro_y = max_loc[1] + h // 2
|
||||
log(f"Botão encontrado! Confiança: {max_val:.2f} | Posição: ({centro_x}, {centro_y})")
|
||||
return (centro_x, centro_y)
|
||||
else:
|
||||
log(f"Botão NÃO encontrado. Melhor confiança: {max_val:.2f} (necessário >= {confianca})")
|
||||
return None
|
||||
|
||||
|
||||
def main() -> None:
|
||||
log("=" * 60)
|
||||
log("Sistema de Cliques Automáticos iniciado")
|
||||
log(f"Intervalo mínimo entre cliques: {INTERVALO_MINIMO_CLIQUE}s")
|
||||
log(f"Intervalo máximo entre cliques: {INTERVALO_MAXIMO_CLIQUE}s")
|
||||
log(f"Aguardar antes do 1º clique: {INTERVALO_PRIMEIRO_CLIQUE}s")
|
||||
log(f"Máximo de cliques por sessão: {MAXIMO_CLIQUES_POR_SESSAO}")
|
||||
log(f"Intervalo entre sessões: {INTERVALO_ENTRE_SESSOES}s")
|
||||
log(f"Máximo de falhas antes de encerrar: {MAXIMO_FALHAS}")
|
||||
log(f"Horário de funcionamento: {HORA_INICIO} às {HORA_FIM}")
|
||||
log(f"Confiança mínima: {CONFIANCA}")
|
||||
log(f"Imagem do botão: {IMAGEM_BOTAO}")
|
||||
log("=" * 60)
|
||||
log("Pressione CTRL+C para parar.")
|
||||
|
||||
primeiro_clique = True
|
||||
falhas_consecutivas = 0
|
||||
total_cliques = 0
|
||||
cliques_na_sessao = 0
|
||||
numero_sessao = 1
|
||||
|
||||
try:
|
||||
while True:
|
||||
agora = datetime.now()
|
||||
|
||||
if not dentro_horario(HORA_INICIO, HORA_FIM):
|
||||
log(f"[Sessão {numero_sessao}] Fora do horário permitido ({agora.strftime('%H:%M:%S')}).")
|
||||
log(f"Pausando até {HORA_INICIO}...")
|
||||
falhas_consecutivas = 0
|
||||
cliques_na_sessao = 0
|
||||
time.sleep(30)
|
||||
continue
|
||||
|
||||
if primeiro_clique:
|
||||
log(f"--- Sessão {numero_sessao} iniciada ---")
|
||||
log(f"Aguardando {INTERVALO_PRIMEIRO_CLIQUE}s antes do primeiro clique...")
|
||||
time.sleep(INTERVALO_PRIMEIRO_CLIQUE)
|
||||
primeiro_clique = False
|
||||
|
||||
posicao = encontrar_botao(IMAGEM_BOTAO, CONFIANCA)
|
||||
|
||||
if posicao:
|
||||
x, y = posicao
|
||||
log(f"[Sessão {numero_sessao}] Clicando em ({x}, {y})...")
|
||||
pyautogui.click(x, y)
|
||||
total_cliques += 1
|
||||
cliques_na_sessao += 1
|
||||
log(f"Clique executado com sucesso. Total geral: {total_cliques} | Sessão {numero_sessao}: {cliques_na_sessao}/{MAXIMO_CLIQUES_POR_SESSAO}")
|
||||
falhas_consecutivas = 0
|
||||
else:
|
||||
falhas_consecutivas += 1
|
||||
log(f"[Sessão {numero_sessao}] Botão não encontrado. Falhas consecutivas: {falhas_consecutivas}/{MAXIMO_FALHAS} | Total de cliques: {total_cliques}")
|
||||
if falhas_consecutivas >= MAXIMO_FALHAS:
|
||||
log(f"Máximo de falhas ({MAXIMO_FALHAS}) atingido. Encerrando sistema.")
|
||||
log(f"Total de cliques realizados com sucesso: {total_cliques}")
|
||||
sys.exit(1)
|
||||
|
||||
# Verifica se atingiu o máximo de cliques da sessão
|
||||
if cliques_na_sessao >= MAXIMO_CLIQUES_POR_SESSAO:
|
||||
log(f"--- Sessão {numero_sessao} finalizada: {cliques_na_sessao} cliques ---")
|
||||
numero_sessao += 1
|
||||
cliques_na_sessao = 0
|
||||
log(f"Aguardando {INTERVALO_ENTRE_SESSOES}s até a próxima sessão (Sessão {numero_sessao})...")
|
||||
time.sleep(INTERVALO_ENTRE_SESSOES)
|
||||
primeiro_clique = True
|
||||
continue
|
||||
|
||||
intervalo = gerar_intervalo_aleatorio(INTERVALO_MINIMO_CLIQUE, INTERVALO_MAXIMO_CLIQUE)
|
||||
log(f"[Sessão {numero_sessao}] Aguardando {intervalo}s até o próximo ciclo...")
|
||||
time.sleep(intervalo)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
log(f"\nSistema interrompido pelo usuário (CTRL+C). Total de cliques: {total_cliques}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user