A criação do Whatsapp bot em Python. O guia completo

Repositório com uma fonte bot

Mostraremos como escrever um simples bot do whatsapp em Python usando a API do WhatsApp.

O bot de demonstração irá atender aos comandos recebidos na forma de mensagens regulares no WhatsApp e responder a eles. Agora, no nosso ChatBot de demonstração, existe a seguinte funcionalidade:

  • Exibição da lista de comandos
  • Exibição do ID do chat atual
  • Exibição da hora atual do servidor no qual o bot está sendo executado.
  • Exibição do nome
  • Envio de arquivos de diferentes formatos (pdf, jpg, doc, mp3, etc.)
  • Envio de mensagens de voz pré-gravadas
  • Envio de coordenadas geográficas (locais)
  • Criação da conferência (grupos)

Atenção: para que o bot funcione, o telefone deve estar sempre conectado à Internet e não deve ser usado para o Whatsapp Web

Primeiros passos

Autorização do Whatsapp via código QR

No início, conectaremos imediatamente o whatsapp ao nosso script (roteiro), de modo que, à medida que escrevemos o código, verificamos sua operação. Para fazer isso, vá para sua conta pessoal e obtenha um código QR lá. Em seguida, abra o WhatsApp no seu celular, vá para Configurações -> WhatsApp Web -> Digitalize um código QR.

Agora, para que o servidor execute o nosso script (roteiro) com novas mensagens, você precisa especificar WebHook URL. WebHook URL este é o link para o qual serão enviados os dados JSON com informações sobre mensagens ou notificações recebidas, usando o método POST. Portanto, para o bot funcionar, precisamos de um servidor que receba e processe esses dados. Ao escrever este artigo, implantamos um servidor usando a micro-framework FLASK. Ele permite que você responda convenientemente às solicitações recebidas e processá-los. 

Obtenha acesso gratuito à API do WhatsApp

Escrevemos a inicialização da classe bot

Criamos o arquivo “wabot.py” e nele descrevemos a classe do nosso bot. Necessitamos importar os dados da biblioteca:

                        import json
import requests
import datetime
                    

A biblioteca json é a responsável pela elaboração do formato Json. Requests – precisamos para acessar a API do site.

Em seguida, criamos a classe WABot.

                        class WABot():
def __init__(self, json):
    self.json = json
    self.dict_messages = json['messages']
    self.APIUrl = 'https://eu41.chat-api.com/instance12345/'
    self.token = 'abcdefg'
                    

Nele, descreveremos o construtor da classe, que por padrão aceitará json aquele que conterá informações sobre as mensagens recebidas (o Webhook aceitará e transmitirá json para a nossa classe). Para descobrir como será o json recebido, acesse a conveniente seção de testes que fornecemos na sua conta pessoal. Nele você pode testar solicitações e Webhook.

Aqui definimos os valores aos atributos de classe. Dict_messages – Um dicionário que contém informações de uma mensagem em um arquivo json que recebemos.

                        self.json = json
self.dict_messages = json['messages']
                    

Você pode visualizar a estrutura json na seção de teste em "Verificação WebHook". Você precisa executar uma verificação e enviar mensagens para o seu chat do whatsapp. Na tela, aparecerá um json, enviado ao webhook.

                        self.APIUrl = 'https://eu41.chat-api.com/instance12345/'
self.token = 'abcdefg'
                    

É necessário substituir os seus dados APIUrl e token, nós os usaremos para formular uma solicitação para a API.

Escrevemos a funcionalidade bot

Envio de solicitações

Para funcionar, precisamos enviar solicitações para a API. Escreveremos uma função que irá gerar solicitações e enviá-las com base em nossos parâmetros.

                        def send_requests(self, method, data):
url = f"{self.APIUrl}{method}?token={self.token}"
headers = {'Content-type': 'application/json'}
answer = requests.post(url, data=json.dumps(data), headers=headers)
return answer.json()
                    

send_requests - aceita dois parâmetros: method e data.

  • method determina qual método ChatAPI deve ser elegido.

  • data contém os dados necessários para a transferência.

Mais detalhes sobre todos os métodos podemos ler na documentação. Data – é um dicionário de dados a partir do qual iremos formar json e transferi-lo usando o método Post no servidor. (Assim que para a nossa funcionalidade de bot apenas os métodos Post são necessários, somente eles serão utilizados por nós).

Nesta fase, formamos a linha de solicitação para a API.

                        url = f"{self.APIUrl}{method}?token={self.token}"
                    

Then we have to define header Content-Type and mark it as Application/JSON since we will always send our data in JSON format.

                        headers = {'Content-type': 'application/json'}
                    

Agora, formamos uma solicitação completa usando requests.post e transferimos nossos dados para o servidor api. Json.dump(data) – serializa nosso dicionário data no formato json.

                        answer = requests.post(url, data=json.dumps(data), headers=headers)
return answer.json()
                    

Retorna a função de resposta do servidor para o formato json.

Enviando mensagens

send_message - aceita dois parâmetros: chatId e text.

  • ChatID – Id do chat, onde você deve enviar uma mensagem

  • Text – Texto da mensagem

Agora, escreveremos o método que irá enviar mensagens para o nosso chat.

                        def send_message(self, chatID, text):
    data = {"chatID" : chatID,
            "body" : text}
answer = self.send_requests('sendMessage', data)
return answer
                    

Formamos o dicionário data, que contém o corpo de "chatId" - Id, para o qual você deseja enviar uma mensagem e o corpo ‘body’ com o texto que precisamos.

                    data = {"chatID" : chatID,
"body" : text}

Em seguida, transferimos nossos dados para o método que escrevemos na etapa anterior.

                    answer = self.send_requests('sendMessage', data)
return answer

Para enviar uma mensagem para o Chat Api, utilizamos o método "sendMessage", é por isso que o passamos para funções como parâmetro junto com o nosso dicionário data. E retornamos a resposta do servidor.

Saudação

O método welcome será elegido pelo comando "hi" do bot e ao inserir um comando inexistente.

  • ChatID – Id do chat, onde você deve enviar uma mensagem

  • noWelcome – Variável booleana que determina qual texto será enviado para o chat: uma saudação ou uma lista de comandos. Por padrão False.

                    def welcome(self,chatID, noWelcome = False):
        welcome_string = ''
        if (noWelcome == False):
            welcome_string = "WhatsApp Demo Bot Python\n"
        else:
            welcome_string = """Incorrect command
Commands:
1. chatid - show ID of the current chat
2. time - show server time
3. me - show your nickname
4. file [format] - get a file. Available formats: doc/gif/jpg/png/pdf/mp3/mp4
5. ptt - get a voice message
6. geo - get a location
7. group - create a group with the bot"""
return self.send_message(chatID, welcome_string)

Formamos nossa linha com a mensagem com base na variável noWelcome e transferimos para a função send_message como o texto a ser enviado.

Exibição do ChatID

def show_chat_id(self,chatID):
return self.send_message(chatID, f"Chat ID : {chatID}")

Exibição do tempo

def time(self, chatID):
t = datetime.datetime.now()
time = t.strftime('%d:%m:%Y')
return self.send_message(chatID, time)

Função me

Exibe informações sobre o nome do interlocutor pelo comando ‘me’

def me(self, chatID, name):
return self.send_message(chatID, name)

Função file

Envia um arquivo com o formato especificado para a caixa de diálogo

  • ChatID – Id do chat, onde você deve enviar uma mensagem

  • format – formato de arquivo a ser enviado. Todos os arquivos enviados são armazenados no servidor

def file(self, chatID, format):
availableFiles = {'doc' : 'document.doc',
                'gif' : 'giffile.gif',
                'jpg' : 'jpgfile.jpg',
                'png' : 'pngfile.png',
                'pdf' : 'presentation.pdf',
                'mp4' : 'video.mp4',
                'mp3' : 'mp3file.mp3'}
if format in availableFiles.keys():
    data = {
                'chatId' : chatID,
                'body': f'https://domain.com/Python/{availableFiles[format]}',
                'filename' : availableFiles[format],
                'caption' : f'Get your file {availableFiles[format]}'
    }
return self.send_requests('sendFile', data)

Aqui, criamos um dicionário que contém os formatos que precisamos como chaves e como valores - os nomes dos arquivos que estão no servidor e aguardam o envio:

availableFiles = {'doc' : 'document.doc',
'gif' : 'giffile.gif',
'jpg' : 'jpgfile.jpg',
'png' : 'pngfile.png',
'pdf' : 'presentation.pdf',
'mp4' : 'video.mp4',
'mp3' : 'mp3file.mp3'}

Em seguida, verificamos se existe um formato em nosso dicionário que o usuário transmitiu.

Se existir, formamos uma solicitação para enviar o arquivo, onde:

if format in availableFiles.keys():
data = {
        'chatId' : chatID,
        'body': f'https://domain.com/Python/{availableFiles[format]}',
        'filename' : availableFiles[format],
        'caption' : f'Get your file {availableFiles[format]}'
}
return self.send_requests('sendFile', data)
  • ChatID – Id do chat, onde você deve enviar uma mensagem

  • Body – link direto para o arquivo que deseja enviar

  • Filename – nome do arquivo

  • Caption – texto que será enviado junto com o arquivo

Formamos uma solicitação send_requests com o parâmetro "sendFile" e passamos nossos dados para ele.

Função ptt

Envie uma mensagem de voz para uma conversa

def ptt(self, chatID):
data = {
"audio" : 'https://domain.com/Python/ptt.ogg',
"chatId" : chatID }
return self.send_requests('sendAudio', data)

Formamos um dicionário de nossos dados, onde:

  • ChatID – Id do chat, onde você deve enviar uma mensagem

  • audio – link direto para o arquivo de formato ogg

Enviamos uma solicitação para a api usando o método "sendAudio"

Função geo

Envie geo-coordenadas

def geo(self, chatID):
data = {
    "lat" : '51.51916',
    "lng" : '-0.139214',
    "address" :'Your address',
    "chatId" : chatID
}
answer = self.send_requests('sendLocation', data)
return answer
  • ChatID – Id do chat, onde você deve enviar uma mensagem

  • lat – coordenadas predefinidas

  • lng – coordenadas predefinidas

  • address – seu endereço ou qualquer linha que você precisa.

Depois de formar o dicionário, enviamos uma solicitação para a API usando o método "sendLocation"

Função group

Crie grupo, onde estará você e o bot

def group(self, author):
phone = author.replace('@c.us', '')
data = {
    "groupName" : 'Group with the bot Python',
    "phones" : phone,
    'messageText' : 'It is your group. Enjoy'
}
answer = self.send_requests('group', data)
return answer

author – o corpo json enviado pelo webhook contém informações sobre quem enviou a mensagem.

Este corpo contém informações sobre o número do usuário, mas com símbolos adicionais. Elegemos a função replace e as excluímos, deixando apenas o número de telefone:

phone = author.replace('@c.us', '')

Formamos dados:

data = {
"groupName" : 'Group with the bot Python',
"phones" : phone,
'messageText' : 'It is your group. Enjoy'}
  • groupName – nome da conferência após sua criação

  • phones – telefones dos participantes da conferência, você pode transferir a matriz de vários celulares

  • messageText – primeira mensagem na conferência

Enviamos a solicitação usando o método 'group'

Processamos solicitações de usuários

Nós descrevemos toda a funcionalidade do nosso bot de demonstração. Agora precisamos organizar a lógica do bot para que ele possa responder aos comandos e interagir com o usuário. Para fazer isso, descrevemos mais uma função

def processing(self):
if self.dict_messages != []:
    for message in self.dict_messages:
        text = message['body'].split()
        if not message['fromMe']:
            id  = message['chatId']
            if text[0].lower() == 'hi':
                return self.welcome(id)
            elif text[0].lower() == 'time':
                return self.time(id)
            elif text[0].lower() == 'chatid':
                return self.show_chat_id(id)
            elif text[0].lower() == 'me':
                return self.me(id, message['senderName'])
            elif text[0].lower() == 'file':
                return self.file(id, text[1])
            elif text[0].lower() == 'ptt':
                return self.ptt(id)
            elif text[0].lower() == 'geo':
                return self.geo(id)
            elif text[0].lower() == 'group':
                return self.group(message['author'])
            else:
                return self.welcome(id, True)
        else: return 'NoCommand'

Esta função será elegida sempre que recebermos dados no nosso webhook.

Vamos analisá-lo em ordem:

Lembra-se do atributo do nosso bot dict_messages, que criamos no início? Ele contém dicionários de mensagens que recebemos. Essa verificação filtra dados que não contêm mensagens. Assim como uma solicitação de webhook pode vir sem uma mensagem.

if self.dict_messages != []:

De fato, podemos receber várias mensagens em uma solicitação e nosso bot deve processá-las. Para que isso aconteça, classificamos todos os dicionários que contêm dict_messages

for message in self.dict_messages:
text = message['body'].split()

Após entrar em um ciclo, declaramos um variável text - que será uma folha de palavras contida em nossa mensagem. Para fazer isso, recorremos ao dicionário message com a chave [‘body’], para obter o texto da mensagem recebida e simplesmente elegemos a função split(), que nos permitirá dividir o texto em palavras.

Em seguida, verificamos se a mensagem recebida não é nossa, acessando a chave "fromMe", que contém True ou False e verifica de quem é a mensagem. 

Preparado um manual sobre como escrever um bot whatsapp em uma python

Se não houver tal verificação, o bot pode entrar em recursão infinita.

Agora, obtemos o ID do chat no mesmo dicionário de mensagens com a chave ['chatId']. Passamos para o primeiro elemento da lista de palavras, trazemos para letras minúsculas para que o bot possa responder às mensagens escritas por Caps Lock ou em letras maiúsculas e minúsculas. Ex: AbCdE…, e compará-lo com os comandos que precisamos.

Após a comparação, simplesmente elegemos a funcionalidade que descrevemos nas etapas anteriores com o parâmetro ID.

Parabéns, nosso bot está pronto!) Agora podemos responder todas às mensagens recebidas.

Você só precisa substituir seu token da sua conta pessoal e instance number. 

Obter chave API

FLASK Servidor

Para o processamento de solicitações, usaremos o servidor Flask. Criaremos um arquivo app.py, importando todas as bibliotecas necessárias.

from flask import Flask, request, jsonify
from wabot import WABot
import json

app = Flask(__name__)

@app.route('/', methods=['POST'])
def home():
    if request.method == 'POST':
        bot = WABot(request.json)
        return bot.processing()

if(__name__) == '__main__':
    app.run()

Inicializamos a variável app, que será a classe Flask.

app = Flask(__name__)

@app.route('/', methods=['POST'])
def home():
    if request.method == 'POST':
        bot = WABot(request.json)
        return bot.processing()

E escreveremos para ele o caminho app.route('/', methods = ['POST']). Esse decorator significa que nossa função home será elegida sempre que nosso servidor flask for acessado por meio de uma solicitação post no caminho principal.

Verificamos que o servidor foi acessado usando o método POST. Criamos um exemplar do nosso bot e transferimos para ele os dados json.

requests.json – permite que você obtenha arquivos json do corpo da solicitação que foi enviado ao nosso servidor.

def home():
if request.method == 'POST':
    bot = WABot(request.json)
    return bot.processing()

E agora elegemos o método bot.processing() em nosso objeto, que é responsável pelo processamento de solicitações.

O bot WhatsApp em Python

Agora você precisa fazer o upload do servidor junto com o bot na hospedagem e especificar seu domínio como um webhook. Sempre que receber uma mensagem os dados serão recebidos e processados no servidor.

Todo o código estará disponível através de um link no GitHab: https://github.com/chatapi/whatsapp-python-bot