Cómo crear un bot de chat para VKontakte usando Python, Django y webhook

¿Por qué otro artículo sobre la creación de un bot de chat?


Tal vez busqué mal, pero no pude encontrar una guía detallada sobre cómo crear un robot de Python usando el marco Django y el enfoque de webhook, que está alojado en una empresa rusa. La mayoría de los materiales hablan sobre el uso del marco Flask y el uso del alojamiento gratuito de Heroku y PythonAnywhere. La experiencia de la comunidad Habr me ayuda, así que decidí tomarme el tiempo para escribir este artículo en agradecimiento. Describiré la experiencia práctica obtenida para permitir que todos los interesados ​​en esto ahorren tiempo y comprendan mejor cómo hacer un bot en Python usando el marco Django en su hosting usando el enfoque webhook.

¿Por qué pagar hosting?


En mi opinión, una versión viable del bot es cuando es independiente de su computadora local y está disponible 24/7. Para hacer esto, necesita un alojamiento en el que exista: un servidor web, un sistema de administración de bases de datos (para desarrollar las capacidades del bot), el registro de un nombre de dominio, la obtención de un certificado SSL y soporte técnico para toda esta economía. Dichos servicios cuestan dinero. Pago el alojamiento de 138 rublos por mes para mantener la infraestructura para que funcione el bot: soporte para Python + Django, MySQL DBMS 25 GB, soporte para SSH.
En la mayoría de las lecciones, vi que una computadora personal se usa como servidor o alojamiento gratuito con restricciones en las horas de trabajo, etc. En los ejemplos, el bot sondea periódicamente el servidor de mensajería en busca de nuevos mensajes de los usuarios. Esta es una carga adicional en los servidores de mensajería, por lo que el bot puede ser "prohibido" por un tiempo. Todo esto, en mi opinión, no es vital para un uso productivo. Pero para la prueba y el entrenamiento es bastante posible.

¿Qué es webhook y por qué?


Para el producto, considero la decisión correcta de usar un webhook, es decir, un enfoque en el que nuestro bot espera mensajes del servidor de mensajería y no lo "martilla" con solicitudes periódicas: ¿hay mensajes nuevos o no? Con un webhook, será así: el usuario escribió un mensaje, el servidor de mensajería lo envió a su bot, recibió el mensaje, lo procesó y respondió.

Por que django


Decidí hacer un bot en Python, así que conecté el soporte de Python en el hosting. Pero no tenía una opción de marco: el alojamiento solo tiene Django. Dicen que funciona Instagram, Pinterest, Bitbucket y Mozilla. Quizás es por eso que el alojamiento lo ofrece.

¿Por qué VKontakte, no Telegram o Viber?


Para pasar de lo simple a lo complejo, era importante para mí encontrar la forma más fácil e intuitiva de configurar un webhook. VKontakte resultó ser el más comprensible para mí debido a la clara ayuda y facilidad de conexión del webhook en el panel de control de la comunidad en la sección "Administración - Trabajando con API". Una descripción de cómo configuré y conecté todo será más detallada. En el futuro quiero que mi bot esté disponible en Viber. Pero con Telegram, todavía no está en camino, porque mi hosting está en Rusia y Telegram está bloqueado de Rusia. Para evitar problemas con Telegram, puedes comprar hosting en el extranjero.

¿Cómo instalar webhook para bot VK?


Nombre de dominio https: // . Primero debe registrar el nombre de dominio del sitio y obtener un certificado SSL.

No quería usar el dominio raíz para el chatbot, así que después de registrar el dominio, hice un subdominio y recibí un certificado SSL.

Hice todas estas manipulaciones en el sitio de alojamiento en mi cuenta personal.
Como resultado, recibí la dirección del sitio mybot.mysite.ru y el certificado SSL.

Obtenemos la clave VK (token) para el bot. Primero creé un grupo cerrado, luego ingresé a la "administración" del grupo, en la sección "Trabajar con API". En la pestaña "Claves de acceso" hay un token, y en la pestaña "Configuración de webhook de la API de devolución de llamada".



Instalar y configurar Django . Tal vez no necesites a Django para ejecutar tu secuencia de comandos de Python, pero no sé cómo.

Usando PuTTY, me conecté al servidor a través de SSH, configuré y activé el entorno virtual.

SSH:
virtualenv-2.7 virtualenv/myEnv . virtualenv/myEnv/bin/activate 

el comando en la primera línea crea un entorno virtual, y el comando en la segunda línea lo activa (observe el espacio después del punto). La versión 2.7 es dictada por el alojamiento y puede diferir en su caso. Por lo tanto, lea la ayuda de alojamiento.

Siguiente Django instalado
SSH:
 pip install 'django<2' 

Instalé la versión de Django no antes de la segunda, porque python 2.7 se usa en el alojamiento y solo funciona con la versión de Django inferior a 2.

E instalé el módulo de Python para trabajar con la API VKontakte
SSH:
 pip install vk 


FTP:
Creó una carpeta para proyectos django en el directorio raíz del alojamiento. La llamó django.

SSH:
Creó un nuevo proyecto.
 cd django/ django-admin.py startproject mybot 

Como resultado, se creará una carpeta con el nombre del proyecto (en nuestro caso es "mybot") en la carpeta / django. Contendrá los archivos de proyecto iniciales creados automáticamente:
/ django
/ mybot - carpeta de proyecto
/ mybot - módulo con la configuración de nuestro proyecto
__init__.py
settings.py
urls.py
wsgi.py
manage.py

Un proyecto en Django es un grupo de aplicaciones. Una aplicación en Django es un programa que realiza las acciones establecidas por el desarrollador.

SSH:
Creó una aplicación.
 cd mybot python manage.py startapp vk_bot 

Fui a la carpeta / django / mybot y creé una nueva aplicación llamada "vk_bot".
Se creó una carpeta con el nombre de la aplicación en la carpeta del proyecto que contiene los archivos de la aplicación creados automáticamente:

/ django
/ mybot - carpeta de proyecto
/ mybot - módulo con la configuración de nuestro proyecto
__init__.py
settings.py
urls.py
wsgi.py
manage.py
/ vk_bot - carpeta de la aplicación
__init__.py
admin.py
apps.py
modelos.py
tests.py
views.py

FTP:
Descargué todos los archivos del proyecto en mi computadora portátil para trabajar con código.
Para trabajar con archivos de proyecto y programación, utilicé la aplicación Atom.

Átomo:
Editó la configuración del proyecto en el archivo /django/mybot/mybot/settings.py
 ... DEBUG = False ... ALLOWED_HOSTS = [ u'mybot.mysite.ru', ] ... 

Átomo:
Configuración de enrutamiento de URL editada en el archivo /django/mybot/mybot/urls.py
 ... urlpatterns = [ url(r'^vk_bot/', include('vk_bot.urls')), ] ... 

FTP:
Creó un archivo /django/mybot/vk_bot/urls.py con el siguiente contenido:
 from django.conf.urls import url from . import views app_name = 'vk_bot' urlpatterns = [ url(r'^$', views.index, name='index'), ] 

Átomo:
Edité el archivo /django/mybot/vk_bot/views.py - agregué una función llamada índice que se ejecutará cuando se solicite la dirección en el navegador
  https://mybot.mysite.ru/vk_bot/ 


views.py
 # -*- coding: utf-8 -*- from __future__ import unicode_literals from django.views.decorators.csrf import csrf_exempt from django.shortcuts import render from django.http import HttpResponse from bot_config import * # import token, confirmation_token and over constants from bot_config.py import json, vk # vk is library from VK """ Using VK Callback API version 5.5 For more ditalies visit https://vk.com/dev/callback_api """ """ From Django documentation (https://docs.djangoproject.com/en/1.11/ref/request-response/) When a page is requested, Django automatically creates an HttpRequest object that contains metadata about the request. Then Django loads the appropriate view, passing the HttpRequest as the first argument to the view function. This argiment is <request> in def index(request): Decorator <@csrf_exempt> marks a view as being exempt from the protection ensured by the Django middleware. For cross site request protection will be used secret key from VK """ @csrf_exempt #exempt index() function from built-in Django protection def index(request): #url: https://mybot.mysite.ru/vk_bot/ if (request.method == "POST"): data = json.loads(request.body)# take POST request from auto-generated variable <request.body> in json format if (data['secret'] == secret_key):# if json request contain secret key and it's equal my secret key if (data['type'] == 'confirmation'):# if VK server request confirmation """ For confirmation my server (webhook) it must return confirmation token, whitch issuing in administration web-panel your public group in vk.com. Using <content_type="text/plain"> in HttpResponse function allows you response only plain text, without any format symbols. Parametr <status=200> response to VK server as VK want. """ # confirmation_token from bot_config.py return HttpResponse(confirmation_token, content_type="text/plain", status=200) if (data['type'] == 'message_new'):# if VK server send a message session = vk.Session() api = vk.API(session, v=5.5) user_id = data['object']['user_id'] # token from bot_config.py api.messages.send(access_token = token, user_id = str(user_id), message = "Hello, I'm bot!") return HttpResponse('ok', content_type="text/plain", status=200) else: return HttpResponse('see you :)') 

En el script views.py , en la función de índice (solicitud) , tuve que deshabilitar la protección integrada en Django CSRF, porque Estaba recibiendo el error "403 Prohibido". CSRF - Protección de falsificación de solicitud de sitio cruzado - protección contra la falsificación de solicitud de sitio cruzado. Cómo funciona CSRF puede leerlo en este artículo .
Para deshabilitar la protección, utilicé el decorador @csrf_exempt . Pero para proporcionar esta protección de todos modos, pero de una manera más simple, utilicé una clave secreta, que está registrada en la sección de administración de grupos en el sitio web de VKontakte.

Este código es responsable de procesar las solicitudes del servidor que enviará para conectar nuestro webhook para el procesamiento de eventos. Digamos simplemente "confirmación" de nuestro webhook.
 if (data['type'] == 'confirmation'):# if VK server request confirmation """ For confirmation my server (webhook) it must return confirmation token, whitch issuing in administration web-panel your public group in vk.com. Using <content_type="text/plain"> in HttpResponse function allows you response only plain text, without any format symbols. Parametr <status=200> response to VK server as VK want. """ # confirmation_token from bot_config.py return HttpResponse(confirmation_token, content_type="text/plain", status=200) 

Tenga en cuenta que mantengo todos los ajustes de configuración en un archivo de configuración de bot independiente bot_config.py y, por lo tanto, lo conecto al comienzo del script:
 from bot_config import * # import token, confirmation_token and over constants from bot_config.py 

bot_config.py
 # -*- coding: utf-8 -*- """ Configuration file for VK bot """ # token issued on the VK group web-administration page token = '...' # confirmation token issued on the VK group web-administration page in "Callback API" section confirmation_token = '...' # secret key for cross site request forgery protection. It will be in each VK server request secret_key = '...' 

Y en este fragmento de código procesa mensajes de usuario:
 if (data['type'] == 'message_new'):# if VK server send a message session = vk.Session() api = vk.API(session, v=5.5) user_id = data['object']['user_id'] # token from bot_config.py api.messages.send(access_token = token, user_id = str(user_id), message = "Hello, I'm bot!") return HttpResponse('ok', content_type="text/plain", status=200) 

Si algo parecía incomprensible, también puede leer el artículo sobre la primera configuración de Django .

La magia para el servidor web . Para configurar el direccionamiento de solicitudes al servidor web, fui al servidor en la carpeta con dominios a través del cliente FTP FileZilla y creé la carpeta " mybot.mysite.ru " allí, puse tres archivos en él, cuyo contenido fue tomado de la ayuda en el alojamiento:

.htaccess
 AddHandler wsgi-script .wsgi RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ /django.wsgi/$1 [QSA,PT,L] RewriteCond %{HTTP:X-Forwarded-Protocol} !=https RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L] 

django.wsgi
 import os, sys virtual_env = os.path.expanduser('~/virtualenv/myEnv') activate_this = os.path.join(virtual_env, 'bin/activate_this.py') execfile(activate_this, dict(__file__=activate_this)) sys.path.insert(0, os.path.join(os.path.expanduser('~'), 'django/mybot')) os.environ['DJANGO_SETTINGS_MODULE'] = 'mybot.settings' from django.core.wsgi import get_wsgi_application application = get_wsgi_application() 

Aquí "myEnv" es el nombre del entorno virtual que creó, "django" es la carpeta en la sección raíz del sistema de archivos en el alojamiento, "mybot" es el nombre del proyecto que creamos usando Django.

index.html
    

"Vincula" nuestro webhook al procesamiento de mensajes en el grupo VKontakte creado.
Para hacer esto, volveremos a la sección para administrar nuestro grupo en el sitio web de VKontakte (vea la captura de pantalla anterior). Ingresaremos nuestra dirección de webhook en el campo "Dirección"
  https://mybot.mysite.ru/vk_bot/ 
y haga clic en el botón "Confirmar". Si nuestra función de índice (solicitud) , escrita en el archivo /django/mybot/vk_bot/views.py funciona correctamente, es decir, no contiene errores tipográficos y errores, aparecerá una marca de verificación verde, que simboliza que todo está bien.

Para que nuestro webhook reciba mensajes del servidor de VKontakte sobre nuevos mensajes de usuario, en la sección para administrar nuestro grupo en el sitio web de VKontakte, en la pestaña "Tipos de eventos", marque la casilla "mensajes entrantes".

Como resultado, nuestro script recibirá estos mensajes en formato json :

 {"type":"message_new","object":{"id":891,"date":1541599508,"out":0,"user_id":1...1,"read_state":0,"title":"","body":"  "},"group_id":1...4,"secret":"uxSBw"} 

Tenga en cuenta que hay un campo "secreto" en el mensaje json . Esta es la misma clave secreta que registré en la sección de administración de grupos del sitio web VKontakte, en lugar de la protección integrada en Django CSRF, que tuve que deshabilitar.

¿Cómo hacer que un bot sea más inteligente y mejor?


Puede crear una base de datos con respuestas para el usuario y enseñarle al bot a elegir la respuesta más cercana en significado a la pregunta del usuario. Hablaré de esto en otro artículo.
Es posible y necesario programar escenarios de interacción del usuario, por así decirlo, para mantener una conversación.

¡Buena suerte en tu trabajo creativo!

Source: https://habr.com/ru/post/es429628/


All Articles