La creación de Whatsapp bot con Python. Guía completa

Repositorio con una fuente de bot

Le mostraremos cómo escribir un simple bot de whatsapp con Python usando la API de WhatsApp.

El bot de demostración atenderá a los comandos recibidos en forma de mensajes regulares en WhatsApp y responderá a ellas. Ahora en nuestra demostración ChatBot, existe la siguiente funcionalidad:

  • Visualización de la lista de comandos
  • Visualización actual de ID de chat
  • Visualización de la hora actual del servidor en el que se ejecuta el bot
  • Visualización de nombre
  • Envío de archivos de diferentes formatos (pdf, jpg, doc, mp3, etc.)
  • Envío de mensajes de voz pregrabados
  • Envío de coordenadas geográficas (locales)
  • Creación de conferencias (grupos)

Advertencia: para que el bot funcione, su teléfono siempre debe estar conectado a Internet y no debe usarse para Whatsapp Web.

Cómo empezar

Autorización de Whatsapp mediante código QR

Al principio, conectaremos inmediatamente WhatsApp a nuestro script, por lo que a medida que escribimos el código, verificamos su funcionamiento. Para hacer esto, vaya a su cuenta personal y obtenga un código QR allí. Luego abra WhatsApp en su teléfono, vaya a Configuración -> WhatsApp Web -> Escanee un código QR.

Ahora, para que el servidor ejecute nuestro script con nuevos mensajes, debe especificar URL de WebHook. URL de WebHook Este es el enlace al que se enviarán los datos JSON con información sobre los mensajes o notificaciones recibidos utilizando el método POST. Entonces, para que el bot funcione, necesitamos un servidor que reciba y procese estos datos. Al escribir este artículo, implementamos un servidor utilizando el micro framework FLASK. Le permite responder convenientemente a las solicitudes entrantes y procesarlas.

Obtenga acceso gratuito a la API de WhatsApp

Escribimos la inicialización de clase bot

Creamos el archivo “wabot.py” y describimos en él la clase de nuestro bot. Necesitamos importar los datos de la biblioteca:

                        import json
import requests
import datetime
                    

La biblioteca json es responsable de preparar el formato Json. Requests – necesitamos acceder a la API del sitio.

Luego creamos la clase 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'
                    

En él, describiremos el constructor de la clase, que por defecto aceptará json que contendrá información sobre los mensajes recibidos (Webhook aceptará y transmitirá a json a nuestra clase). Para saber cómo se verá su json recibido, visite la conveniente sección de pruebas que le proporcionamos en su cuenta personal. En él puedes probar solicitudes y Webhook.

Aquí definimos los valores para los atributos de clase. Dict_messages – un diccionario que contiene información de un mensaje en un archivo json que recibimos.

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

Usted puede visualizar la estructura json en la sección de prueba en "Verificación WebHook". Necesita ejecutar una verificación y enviar mensajes a su chat de whatsapp. En la pantalla aparecerá un json, enviado a webhook.

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

Es necesario sustituir sus datos APIUrl y token, lo utilizaremos para realizar una solicitud de la API.

Escribimos la funcionalidad bot

El envío de solicitudes

Para que funcione, necesitamos enviar solicitudes a la API. Escribiremos una función que generará solicitudes y las enviaremos en función de nuestros 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 - acepta dos parámetros: method e data.

  • method determina qué método de ChatAPI elegir.

  • data contiene los datos requeridos para la transferencia

Más detalles sobre todos los métodos podemos leer en la documentación. Data – es un diccionario de datos desde el cual formaremos json y lo transferiremos utilizando el método Post en el servidor. (En cuanto a nuestra funcionalidad de bot, solo se requieren métodos de publicación, solo los utilizaremos nosotros).

En esta etapa, formamos la línea de solicitud para la API.

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

Luego debes especificar header Contet-Type y marcarlo como Aplicación/Json,porque siempre transferiremos nuestros datos en el formato json

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

Ahora formamos una solicitud completa usando requests.post y transferimos nuestros datos al servidor api. Json.dump(data) – serializa nuestro diccionario data en el formato json.

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

Devuelve la función de respuesta del servidor para el formato json.

El envío de mensajes

send_message - acepta dos parámetros: chatId y text.

  • ChatID – Id chat donde se debe enviar un mensaje

  • Text – Texto del mensaje

Ahora escribiremos el método que enviará mensajes a nuestro chat.

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

Formamos el diccionario data, que contiene el cuerpo de "chatId" - Id, al que desea enviar un mensaje y el cuerpo 'body' con el texto que necesitamos.

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

Luego transferimos nuestros datos al método que escribimos en el paso anterior

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

Para enviar un mensaje a Chat Api, utilizamos el método "sendMessage", por lo que lo pasamos a funciones junto con nuestro diccionario data. Y devolvimos la respuesta del servidor.

Saludo de bienvenida

El método welcome será elegido por el comando "hi" del bot y al insertar una orden inexistente.

  • ChatID – Id de chat, donde debe enviar un mensaje

  • noWelcome – Variable booleana que determina qué texto enviar al chat: un saludo o una lista de comandos. Por defecto 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 nuestra línea con el mensaje basado en la variable noWelcome y lo transferimos a la función send_message como el texto a enviar.

Visualización de ChatID

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

Visualización de la hora

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

Función me

Muestra la información sobre el nombre del interlocutor mediante el comando 'me'

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

Función file

Envía un archivo con el formato especificado a la caja de diálogo

  • ChatID – Id chat donde se debe enviar un mensaje

  • format – formato de archivo que se enviará. Todos los archivos cargados se almacenan en el 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)

Aquí creamos un diccionario que contiene los formatos que necesitamos como claves y como valores - los nombres de los archivos que están en el servidor y en espera de ser enviados:

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

Luego verificamos si hay un formato en nuestro diccionario que el usuario transmitió.

Si es así, solicitamos cargar el archivo, donde:

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 chat donde se debe enviar un mensaje

  • Body – enlace directo al archivo que desea cargar

  • Filename – nombre de archivo

  • Caption – texto que se enviará junto con el archivo

Formamos una solicitud send_requests con el parámetro "sendFile" y le pasamos nuestros datos.

Función ptt

Envía un mensaje de voz a una conversación

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

Formamos un diccionario de nuestros datos, donde:

  • ChatID – Id chat donde se debe enviar un mensaje

  • audio – enlace directo al archivo de formato ogg

Enviamos una solicitud a la api usando el método "sendAudio"

Función geo

Envía 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 chat donde se debe enviar un mensaje

  • lat – coordenadas predefinidas

  • lng – coordenadas predefinidas

  • address – su dirección o cualquier línea que necesite.

Después de formar el diccionario, enviamos una solicitud a la API utilizando el método "sendLocation"

Función group

Cree grupo, donde estarás tú y el 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 – el cuerpo json enviado por webhook contiene información sobre quién envió el mensaje.

Este cuerpo contiene información de número de usuario, pero con símbolos adicionales. Elegimos la función de reemplazo y los eliminamos, dejando solo el número de teléfono:

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

Formamos datos:

data = {
"groupName" : 'Group with the bot Python',
"phones" : phone,
'messageText' : 'It is your group. Enjoy'}
  • groupName – nombre de la conferencia después de su creación

  • phones – teléfonos de los participantes de la conferencia, usted puede transferir la variedad de teléfonos múltiples

  • messageText – primer mensaje en la conferencia

Enviamos la solicitud utilizando el método 'group'

Procesamos las solicitudes de los usuarios

Describimos toda la funcionalidad de nuestro bot de demostración. Ahora necesitamos organizar la lógica del bot para que pueda responder a los comandos e interactuar con el usuario. Para hacer esto, describimos una función más.

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 función se elegirá cada vez que recibamos datos en nuestro webhook.

Vamos a analizarlo en orden:

¿Recuerdas el atributo de nuestro bot dict_messages, que creamos al principio? Contiene diccionarios de mensajes que recibimos. Esta verificación filtra datos que no contienen mensajes. Al igual que una solicitud de webhook puede venir sin un mensaje.

if self.dict_messages != []:

De hecho, podemos recibir múltiples mensajes en una solicitud y nuestro bot debe procesarlos. Para que esto suceda, clasificamos todos los diccionarios que contienen dict_messages.

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

Después de entrar en un ciclo, declaramos una variable de text - que será una hoja de palabras contenida en nuestro mensaje. Para hacer esto, recurrimos al diccionario de mensajes con la clave [‘body’], para obtener el texto del mensaje recibido y simplemente elegimos la función split(), que nos permitirá dividir el texto en palabras.

Luego comprobamos si el mensaje recibido no es nuestro, accediendo a la clave "fromMe", que contiene True o False y verificar de quién es el mensaje.

Preparé un manual sobre cómo escribir un bot whatsapp en una python

Si no hay tal verificación, el bot puede entrar en una recursión infinita.

Ahora obtenemos la ID de chat en el mismo diccionario de mensajes con la clave ['chatId']. Nos movemos al primer elemento de la lista de palabras y lo ponemos en minúsculas para que el bot pueda responder a los mensajes escritos por Caps Lock o en letras mayúsculas y minúsculas. Ej: AbCdE…, y compáralo con los comandos que necesitamos.

Después de la comparación, simplemente elegimos la funcionalidad que describimos en los pasos anteriores con el parámetro ID.

¡Felicitaciones, nuestro bot está listo!) Ahora podemos responder a todos los mensajes entrantes.

Solo necesita reemplazar su token de cuenta personal y instance number

Obtener clave API

Servidor FLASK

Para el procesamiento de solicitudes, usaremos el servidor Flask. Crearemos un archivo app.py, importando todas las bibliotecas necesarias.

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 la variable de la aplicación, que será la clase Flask.

app = Flask(__name__)

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

Y le escribiremos el camino app.route('/', methods = ['POST']). Este decorador significa que nuestra función home será elegido cada vez que se acceda a nuestro servidor flask a través de una solicitud post en el camino principal.

Verificamos que se accedió al servidor utilizando el método POST. Creamos un ejemplar de nuestro bot y le transferimos los datos json.

requests.json – le permite obtener archivos json del cuerpo de la solicitud que se envió a nuestro servidor.

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

Y ahora hemos elegido el método bot.processing() en nuestro objeto, que es responsable de procesar las solicitudes.

Whatsapp bot con Python

Ahora usted debe cargar el servidor junto con el bot de alojamiento y especificar su dominio como webhook. Cada vez que reciba un mensaje, los datos serán recibidos y procesados en el servidor.

Todo el código estará disponible a través de un enlace en githab: https://github.com/chatapi/whatsapp-python-bot