Ultimas do CanalQb

CanalQb - Python - Bots no Telegram: Automatização de serviços no Linux e Windows

@CanalQb

CanalQb - Python - Bots no Telegram: Automatização de serviços no Linux e Windows



Olá, este aqui neste post vou apresentar para vocês um script ideal que eu desenvolvi para a criação de serviços no Linux Ubuntu 18.04 e Windows 10. 
Basicamente em outros sistemas operacionais são os mesmos comandos, mas por causa de normas e diretrizes pode sofrer alguma variação, então se algo der errado, por favor comente.

Antes de você seguir com a leitura deste post, vamos fazer um trato, se uma única linha for útil para você, você se inscreve no meu canal do Youtube, concorda?

Primeiro vou abrir o Script aqui para vocês entenderem as etapas.

Em post como "CanalQb - Python - Importação do TXT para QRcode do Telegram" e "Python - Script gerador de QRCode", eu ensino a vocês como criar um leito de QRcode para utilizar junto ao telegram, então esse não será o foco do post.

Mas vamos lá, para que o script funcione você precisará ter uma pasta inicial, uma raiz.
No meu exemplo estou utilizando uma pasta com o nome bot, a raiz pode ser qualquer nome.

Obviamente, você não irá usar este script apenas para Bots do Telegram, mas sim para todos seus scripts do python, detalhe eu sempre uso o python 3.8.10.

Por este motivo ou detalhar cada trecho do script para vocês, o que ajudará a modificar da forma que desejarem.

Os modulos que estou utilizando e são padrões dentro do Python 3.8.10 são:
os, shutil, getpass, time, ctypes, subprocess, sys, platform
No entanto o ctypes é uma biblioteca padrão, mas algumas funcionalidades podem variar de acordo com o sistema operacional. Portanto, é recomendável verificar se o ctypes está instalado no sistema que você utiliza chamando a instalação dele pelo comando:
pip install ctypes
Então meu Script abre com:
import os
import shutil
import getpass
import subprocess
import time
import ctypes
import sys
import platform
Agora vamos aos def's
# Obtém o caminho do Python a partir do PATH do sistema Windows
def obter_caminho_python():
    caminho_python = None
    paths = os.environ.get("PATH", "").split(";")
    for path in paths:
        if "python" in path.lower() and "scripts" not in path.lower():
            caminho_python = path.strip()
            break
    return caminho_python
Basicamente o def obter_caminho_python informa o caminho do python que você está usando, e será utilizado para gerar um arquivo de lote .bat, mais a frente
def run_as_admin(commands):
    # Verificar se o script já está sendo executado como administrador
    if ctypes.windll.shell32.IsUserAnAdmin():
        for command in commands:
            subprocess.run(command, shell=True)
    else:
        # Chamar um prompt de comando como administrador e executar os comandos
        command_str = " && ".join(commands)
        ctypes.windll.shell32.ShellExecuteW(None, "runas", "cmd.exe", "/c " + command_str, None, 1)
O def run_as_admin é utilizado para executar comando em cmd, só que em modo admin, ao ser chamado, ele solicita a abertura do cmd e pede para você validar a permissão de admin.

Def's explicados vamos continuar o script.
clear = lambda: os.system('cls' if os.name=='nt' else 'clear')  
Esta linha a cima, cria inclui na variável clear a opção de limpar a tela nos 2 ambientes, usando o comando cls para o prompt do windows e o clear para o terminal.
Fica a dica de como incluir comandos simples de terminal usando variável.

Vamos falar de outro comando, o import platform que serve para identificar os sistemas abaixo
"Windows" para sistemas Windows | "Linux" para sistemas Linux | "Darwin" para sistemas macOS | "Java" para sistemas Java | "Java (Jython)" para sistemas Jython | "Java (IronPython)" para sistemas IronPython | "FreeBSD" para sistemas FreeBSD | "NetBSD" para sistemas NetBSD | "OpenBSD" para sistemas OpenBSD | "SunOS" para sistemas Solaris e SunOS | "AIX" para sistemas AIX | "Java (Stackless)" para sistemas Stackless Python | "Java (PyPy)" para sistemas PyPy
sistema_operacional = platform.system() 
if sistema_operacional == "Windows":
    idsystem = 'w'
elif sistema_operacional == "Linux":
    idsystem = 'l'
else:
    idsystem = 'g'
Então basicamente meu script vai identificar se é Windows ou Linux, não o plataform não consegue identificar exclusivamente o Android, você vai precisar de outro módulo.

Como eu mencionei você irá precisar ter uma pasta raiz.
esta pasta raiz, possui algumas subpastas, pastas que este script irá usar para conseguir alguns dados automáticos, outras para alguns dados para interagir com o usuário, e outras que possui alguns backups criadas por ele, e um de scripts de arquivos mortos.
diretorio_atual = os.getcwd()
pastas = [nome for nome in os.listdir(diretorio_atual) if os.path.isdir(os.path.join(diretorio_atual, nome))]
pastas_excluidas = ["QR", "Mortos", "serviceslinux", "serviceswindows"]
pastas_filtradas = [pasta for pasta in pastas if pasta not in pastas_excluidas]
O que a parte do Script acima faz, é controlar quais pastas eu não desejo que o script retorne na próxima pergunta para o usuário
clear()

Apenas limpando a tela como mencionado anteriormente

print("\n\t\tPastas disponíveis:")
for i, pasta in enumerate(pastas_filtradas):
    lista_pastas = " | ".join(f"{i+1}. {pasta}" for i, pasta in enumerate(pastas_filtradas))
print("\n\t\t",lista_pastas,"\n")
print("\t\t", "-" * 40)
opcao = input("\t\tDigite o número da pasta que deseja visualizar os arquivos: ")
Agora que eu ocultei a visualização das pastas que eu não desejo, ele simplesmente irá mostrar as demais subpastas da raiz.

Esta é a minha visão de pastas e arquivos
Observe o print abaixo, executado via putty para acessar o linux e cmd via windows que as pastas que eu descartei acima não aparecem na consulta

Putty


CMD

Então ao você escolher a opção desejada, ele vai listar todas os arquivos da pasta
if opcao.isdigit() and 0 < int(opcao) <= len(pastas_filtradas):
    pasta_selecionada = pastas_filtradas[int(opcao)-1]
    caminho_pasta_selecionada = os.path.join(diretorio_atual, pasta_selecionada)
    arquivos = os.listdir(caminho_pasta_selecionada)
    
    # Filtrar apenas os arquivos com extensão .py
    arquivos_py = [arquivo for arquivo in arquivos if arquivo.endswith(".py")]

    # Imprimir os arquivos com extensão .py
    print(f"\n\t\t Arquivos na pasta '{pasta_selecionada}':")
    for arquivo in arquivos_py:
        print("\t\t", arquivo)
else:
    print("Opção inválida. Certifique-se de selecionar um número válido.")

O script acima, faz imprimir em tela apenas para conferencia, os nomes dos arquivos que estão dentro da pasta, mas só irá imprimir os arquivos de extensão .py


Acima o exemplo da consulta feita da opção 1, a subpasta e seus arquivos e pastas internos, mas olhe no prompt ele apenas retorna o arquivo .py
diretorio_atual = os.getcwd()
pasta_qr = os.path.join(diretorio_atual, "QR")
if not os.path.exists(pasta_qr) or not os.path.isdir(pasta_qr):
    print("A pasta QR não existe.")
    exit()
#clear()
arquivos_session = [arquivo for arquivo in os.listdir(pasta_qr) if arquivo.lower().endswith("session")]

print("\n\t\tArquivos session disponíveis gerados em QR:\n")
for i, arquivo in enumerate(arquivos_session):
    print(f"\t\t{i+1}. {arquivo}")
print("\n\t\t", "-" * 40)
opcao = input("\t\tDigite o número do arquivo session que deseja usar: ")
Esta parte acima, ele vai consultar a pasta oculta QR, e ler todos os arquivos que estão dentro dela com o a extensão .session
Todos os arquivos da pasta bot/QR

Lendo apenas os arquivos .sessionda pasta bot/QR

Assim que você definir o nome do arquivo, ele vai definir o caminho deste arquivo para a variavel caminho_arquivo_selecionado 
if opcao.isdigit() and 0 < int(opcao) <= len(arquivos_session):
    arquivo_selecionado = arquivos_session[int(opcao)-1]

caminho_arquivo_selecionado = os.path.join(pasta_qr, arquivo_selecionado)
E então vem a mesclagem do sistema e do arquivo
if arquivo_selecionado.lower().startswith("l"):
        if idsystem == "w":
            print("\n\t\tO arquivo de sessão é para Linux, você está no ambiente errado\n")
            exit()
if arquivo_selecionado.lower().startswith("w"):
        if idsystem == "l":        
            print("\n\t\tO arquivo de sessão é para Windows, você está no ambiente errado\n")
            exit()
            
print(f"\n\t\t{arquivo_selecionado} será espelho para os arquivos da pasta {pasta_selecionada}\n")
O Script acima, faz 2 condições IF básicas, os arquivos gerado pelo qnew.py dentro da pasta QR, respeita o ambiente do sistema operacional que você está, e inclui como primeira leta l para o linux e w para o Windows. E então o script faz o trabalho de cruzar as informações do ambiente que você está e qual vai usar.

Se você estiver no Linux e pedir o arquivo com inicio w, ele encerra o script
Se você estiver no Windows e pedir o arquivo com inicio l, ele encerra o script

Resolvido esta parte acima, agoravai fazer um trabalho mais amoroso, este é praticamente se você for mesmo usar este script para o telegram da mesma forma que eu uso.
for arquivo in arquivos:
    nome_arquivo, extensao_arquivo = os.path.splitext(arquivo)
    novo_nome_arquivo = nome_arquivo + ".session"
    caminho_destino = os.path.join(diretorio_atual, novo_nome_arquivo)
    shutil.copy(caminho_arquivo_selecionado, caminho_destino)

print("\t\tGerado Sessions com sucesso!")
Acima o comando vai fazer um copy (CTRL+C) do comando que você selecionou o arquivo .session , e salvar com o nome de cada arquivo que você possui dentro da pasta selecionada inicialmente.


Agora é hora de trabalhar com o tempo de execução dos arquivos.
Como vocês já devem saber, Faucets de Bot's de Telegram, são ruins por que você é obrigado a ficar entrando nele de 5 em 5 minutos, de hora em hora, e isso realmente cansa.
Mas com meus script ele faz o clique automático, mas precisamos criar uma rotina de repetição para quando atingir o tempo mínimo de clique, e é ai que o service do Windows e do Linux servem.

Então neste momento, é onde eu defino o tempo de serviço, de quanto em quanto tempo eu preciso que ele reinicie o script, e ele possa clicar no meu faucet, mas não se prenta a bot de telegram, as informações baixo são importantes para varias atividades, rotinas de manutenção, execução de outros scripts, entre tantas coisas que você pode fazer e deixar seu sistema operacional trabalhando.
# Pergunta sobre o tempo de reinício
print(f"\n\t\tAgora escolha o temporizador de reinicio, para o arquivo {pasta_selecionada}.service")
print("\n\t\t1) 1 min | 2) 15 min | 3) 30 min | 4) 45 min | 5) 60 min | 6) 120 min | 7) 12 horas | 8) 1 dia" )
print("\n\t\t", "-" * 40)

opcao_reinicio = input("\n\t\tDigite o número do tempo de reinício desejado: ")

tempos_reinicio = {
    "1": 60,           # 1 minuto
    "2": 900,          # 15 minutos
    "3": 1800,         # 30 minutos
    "4": 2700,         # 45 minutos
    "5": 3600,         # 60 minutos
    "6": 7200,         # 120 minutos
    "7": 43200,        # 720 minutos (12 horas)
    "8": 86400         # 1440 minutos (1 dia)
}
if opcao_reinicio in tempos_reinicio:
    tempo_reinicio = tempos_reinicio[opcao_reinicio] + 1
Esta parte do script, ela pergunta o tempo que você quer para seus bots, eu coloquei os tempos mais habituais, mas é totalmente editável para sua melhor escolha


Definido sua escolha de tempo acima, ele irá dependendo do sistema operacional que você está, criar um service, a primeira parte do Script dentro de if opcao_reinicio in tempos_reinicio: é para o Linux e depois para o Windows, vou falar sobre os 2.

Criando o Service para Linux:
if arquivo_selecionado.lower().startswith("l"):
    if idsystem == "l":
    # Obter o nome do usuário
    #usuario = getpass.getuser() #retorna o usuario root da sua maquina, comum root
    usuario = os.getlogin() #retorna o usuario que está executando a acao

    # Criar o arquivo de serviço
    nome_arquivo_service = pasta_selecionada + ".service"
    caminho_arquivo_service = os.path.join(diretorio_atual, "serviceslinux", nome_arquivo_service)
Nesta parte ele vai entrar pelo inicial do arquivo, não precisava, mas como foi um dos primeiros comandos acabei mantendo, e agora faz parte, depois ele consulta o sistema operacional que você está, as 2 primeiras linhas já vimos durante o inicio deste post.
a variavel usuario pega o perfil do usuário, ou se você desejar criar o service para root basta remover o comentário da linha  #usuario = getpass.getuser() e comentar a linha usuario = os.getlogin()
Então ele inicia o processo de criação do arquivo service dentro da pasta serviceslinux, usando o nome da pasta da sua primeira escolha, e salvando com o nome por exemplo dozehoras.service



Vamos lá, escolhemos a pasta
Escolhemos a sessão
Escolhemos o tempo

E ele gerou o arquivo service na pasta serviceslinux com o mesmo nome, de acordo com os prints acima.
Agora precisamos alimentar esse arquivo .service 
with open(caminho_arquivo_service, "w") as arquivo_service:
arquivo_service.write(f"[Unit]\n")
arquivo_service.write(f"Description=Serviços de 1 hora\n")
arquivo_service.write(f"After=multi-user.target\n\n")
arquivo_service.write(f"[Service]\n")
arquivo_service.write(f"Type=simple\n")
arquivo_service.write(f"ExecStart=/usr/bin/python -c \"import glob, os; [os.system('python3 {{}}'.format(script)) for script in glob.glob('{caminho_pasta_selecionada}/*.py')]\"\n")
arquivo_service.write(f"User={usuario}\n")  # Substituir o valor do usuário
arquivo_service.write(f"WorkingDirectory={caminho_pasta_selecionada}\n")
arquivo_service.write(f"Restart=always\n")
arquivo_service.write(f"RestartSec={tempo_reinicio}\n\n")
arquivo_service.write(f"[Install]\n")
arquivo_service.write(f"WantedBy=multi-user.target\n")
Basicamente está é a estrutura do service que eu crio para que o serviço do Linux consiga ler todos os arquivos dentro da pasta que escolhemos, em um único service e chamando o python uma única vez. veja as variáveis que estão em vermelho
  • caminho_pasta_selecionada - por exemplo neste post eu usei a pasta dozehoras, então dentro dessa variável vai conter o caminho completo desta pasta
  • usuario - acabamos de falar dele, é seu usuário de perfil ou root
  • tempo_reinicio - foi o tempo determinado de sua ultima escolha 
Continuando
 # Obtendo o diretório atual
diretorio_atual = os.getcwd()

#Nome do serviço baseado na pasta selecionada
nome_servico = pasta_selecionada + ".service"

# Parando e desativando o serviço
comando_parar_servico = f"systemctl stop {nome_servico}"
comando_desativar_servico = f"systemctl disable {nome_servico}"
#clear()
subprocess.run(comando_parar_servico, shell=True, capture_output=True, text=True)
subprocess.run(comando_desativar_servico, shell=True)

Esta rotina vai entrar na raiz Bot, e vai fazer o nome do arquivo concatenando a variável da pasta_selecionada + o texto .service e alimentando a variável nome_servico 

com a variável alinemtada, ele vai parar e desativar o serviço ativo caso exista, eu não fiz tratativa de erro se não existir, mas não interfere.

Então agora ele começa a copiar o arquivo service que o script criou e envia para a pasta /etc/systemd/system existem linux que o caminho é diferente, então é importante ficar de olho nesta parte!
 # Caminho completo para o arquivo de serviço
caminho_servico_origem = os.path.join(pasta_services, nome_servico)

# Verificando se o arquivo de serviço existe
if not os.path.exists(caminho_servico_origem) or not os.path.isfile(caminho_servico_origem):
print(f"\n\t\tO arquivo de serviço '{nome_servico}' não existe na pasta 'serviceslinux'.")
exit()

# Caminho para o diretório de destino
destino_services = "/etc/systemd/system"

# Verificando se o diretório de destino existe
if not os.path.exists(destino_services) or not os.path.isdir(destino_services):
print("\n\t\tO diretório '/etc/systemd/system' não existe.")
exit()

# Caminho completo para o arquivo de serviço de destino
caminho_servico_destino = os.path.join(destino_services, nome_servico)

# Copiando o arquivo de serviço para o diretório de destino
shutil.copy(caminho_servico_origem, caminho_servico_destino)
Basicamente nesta parte ele vai copiar o arquivo que você criou .service para a pasta system para poder rodar o serviço, então:
# Executando o comando systemctl daemon-reload
comando_daemon_reload = "systemctl daemon-reload"
subprocess.run(comando_daemon_reload, shell=True)

# Ativando e iniciando o serviço
comando_ativar_servico = f"systemctl enable {nome_servico}"
comando_iniciar_servico = f"systemctl start {nome_servico}"
comando_status_servico = f"systemctl status {nome_servico} | cat"

subprocess.run(comando_ativar_servico, shell=True)
subprocess.run(comando_iniciar_servico, shell=True)
subprocess.run(comando_status_servico, shell=True)

print(f"\n\t\tO serviço '{nome_servico}' foi copiado para '/etc/systemd/system', ativado e iniciado com sucesso.")
Após ele concluir a copia, ele inicia este processo de execução padrão de serviços do Linux.
daemon-reload
 ele vai recarregar as configurações do linux, para permitir incluir seus services novos
então vai ativar o service para ser usado no sistema
vai iniciar o service e imprimir um status, apenas para validar se foi criado.

Comandos de consulta:
ver se o arquivo existe ls /etc/systemd/system/dozehoras.service
ver o status do arquivo systemctrl status dozehoras
Quer mais comandos?

Concluído a parte do Serviço Linux

Vamos ao Serviço do Windows
lembra que ele utiliza as duas Def's no inicio do post

O Windows além de criar um service, será necessário criar um arquivo de lote para que ele possa chamar dentro do service, por este motivo é indicado você proteger sua pasta onde o Bat ficará salvo para evitar edições futuras por espertinhos (Mas é claro se alguém for invadir, não vai invadir para ficar pensando no seu bat, ele vai fritar e pegar tudo que se tem, e não zuar um bat)

Bom vamos lá
 
elif arquivo_selecionado.lower().startswith("w"):
    if idsystem == "w":
        # Código para Windows
        print(f"\n\t\tVocê selecionou o arquivo: {arquivo_selecionado} para todos os arquivos da pasta {pasta_selecionada} no Windows.")

        # Nome do serviço baseado na pasta selecionada
        nome_servico = "0." + pasta_selecionada + "_Service"
            
        # Criar arquivo .bat para Windows
        nome_arquivo_bat = pasta_selecionada + ".bat"
        caminho_arquivo_bat = os.path.join(diretorio_atual, "serviceswindows", nome_arquivo_bat)

Igual ao do Linux, as 2 primeiras linhas, foram a primeira coisa que eu fiz no script, então mantive
a variável nome_servico é responsável por criar o arquivo de lote dentro da pasta serviceswindows
with open(caminho_arquivo_bat, "w") as arquivo_bat:
    arquivo_bat.write("@echo off\n")
    arquivo_bat.write("setlocal enabledelayedexpansion\n\n")
    arquivo_bat.write(f"set \"python_path={obter_caminho_python()}\python.exe\"\n")
    arquivo_bat.write(f"set \"script_folder={pasta_selecionada}\"\n\n")
    arquivo_bat.write("for %%f in (\"%script_folder%\\*.py\") do (\n")
    arquivo_bat.write("\t%python_path% \"%%f\"\n")
    arquivo_bat.write(")\n\n")
    arquivo_bat.write("endlocal\n")
Uma vez que o arquivo lote está criado, ele simplesmente vai alimentar o arquivo com as informações acima
a variavel obter_caminho_python é o def para retornar o caminho do python 
os demais comandos são os mesmos do linux.
servicowindows = [
    f"@(sc query {nome_servico} > nul && (sc stop {nome_servico} & sc delete {nome_servico} & timeout /t 1) || (timeout /t 1)) & (sc create {nome_servico} binPath= \"{caminho_arquivo_bat}\" start= auto & sc failure {nome_servico} actions= restart/{tempo_reinicio*1000}/restart/{tempo_reinicio*1000}/restart/{tempo_reinicio*1000}// reset= 86400 & sc start {nome_servico})",
    ":servicocompleto",
    "timeout 10",  # Adicionando um segundo de espera
    ":servicoinexistente"
                ]

run_as_admin(servicowindows)
variavel nome_servico = é a variavel que vai dar nome ao seu service do windows
variavel tempo_reinicio = é o tempo de reinicio que o servico para loop
variavel caminho_arquivo_bat = caminho onde o arquivo de lote está

Lembrando que está tudo aberto para vocês usarem da forma que decidirem.

Antes de Fazer o Download, lembre de pegar seu API e SUA HASH do TELEGRAM e salvar no arquivo meustelegram da pasta QR


Link para Download: https://cb.run/ZAjR

Atualização, eu criei no Windows 10 64 BITs, mas precisei instalar no Windows 7 32 Bits, e a linha da tarefa muda, então está aqui as alternaticas, inclua o def,

def run_as_admin(commands):
    # Verificar se o script já está sendo executado como administrador
    if ctypes.windll.shell32.IsUserAnAdmin():
        for command in commands:
            subprocess.run(command, shell=True)
    else:
        # Chamar um prompt de comando como administrador e executar os comandos
        command_str = " && ".join(commands)
        ctypes.windll.shell32.ShellExecuteW(None, "runas", "cmd.exe", "/c " + command_str, None, 1)
e depois basta trocar uma linha pela outra.
#------------------------Criando Agenda do Windows --------------------------------------
                os.system(r'schtasks /Delete /TN 0.'+pasta_selecionada+' /F')
                #Windows 10 64 BITS
                #os.system(r'schtasks /Create /XML "'+ os.path.join(diretorio_atual, "serviceswindows", pasta_selecionada + ".xml") +'" /TN "0.'+pasta_selecionada+'"')
                #Windows 7 32 BITs precisa abrir com Administrador
                #command_str = str('schtasks.exe /create /RU SYSTEM /TN "0.' + pasta_selecionada + '" /XML "' + os.path.join(diretorio_atual, "serviceswindows", pasta_selecionada + ".xml") + '"')
                comando1 = str('schtasks /Delete /TN 0.' + pasta_selecionada + ' /F')
                comando2 = str('schtasks.exe /create /RU SYSTEM /TN "0.' + pasta_selecionada + '" /XML "' + os.path.join(diretorio_atual, "serviceswindows", pasta_selecionada + ".xml") + '"')
                run_as_admin([comando1, comando2]) 
#------------------------Criando Agenda do Windows --------------------------------------

 

CanalQb

Nenhum comentário

Comente só assim vamos crescer juntos!

Observação: somente um membro deste blog pode postar um comentário.