Como criar um bot de bate-papo para o VKontakte usando Python, Django e webhook

Por que outro artigo sobre a criação de um bot de bate-papo?


Talvez eu tenha pesquisado mal, mas não consegui encontrar um guia detalhado sobre a criação de um bot python usando a estrutura do Django e a abordagem webhook, hospedada por uma empresa russa. A maioria dos materiais fala sobre o uso da estrutura Flask e a hospedagem gratuita do Heroku e PythonAnywhere. A experiência da comunidade Habr me ajuda, então decidi reservar um tempo para escrever este artigo em gratidão. Descreverei a experiência prática adquirida para permitir que todos os interessados ​​nisso economizem tempo e entendam melhor como criar um bot em Python usando a estrutura do Django em sua hospedagem usando a abordagem webhook.

Por que hospedagem paga?


Na minha opinião, uma versão viável do bot é quando ele é independente do seu computador local e está disponível 24/7. Para fazer isso, você precisa de uma hospedagem na qual haja: um servidor web, um sistema de gerenciamento de banco de dados (para desenvolver os recursos do bot), registro de um nome de domínio, obtenção de um certificado SSL e suporte técnico para toda essa economia. Tais serviços custam dinheiro. Pago hospedagem 138 rublos por mês para manter a infraestrutura para o bot funcionar: suporte para Python + Django, MySQL DBMS 25 GB, suporte para SSH.
Na maioria das lições, vi que um computador pessoal é usado como servidor ou hospedagem gratuita com restrições de horário de trabalho etc. Nos exemplos, o bot consulta periodicamente o servidor de mensagens em busca de novas mensagens dos usuários. Isso é uma carga extra nos servidores de mensagens, para que o bot possa ser "banido" por um tempo. Tudo isso, na minha opinião, não é vital para o uso produtivo. Mas para o teste e o treinamento é bem possível.

O que é webhook e por que é?


Para o produto, considero a decisão correta de usar um webhook, ou seja, uma abordagem na qual nosso bot espera mensagens do servidor de mensagens e não o "martela" com solicitações periódicas: há novas mensagens ou não. Com um webhook, será assim: o usuário escreveu uma mensagem, o servidor do messenger enviou para o seu bot, ele recebeu a mensagem, processou e respondeu.

Por que django


Decidi fazer um bot em python, então liguei o suporte a python na hospedagem. Mas não tive a opção de escolher uma estrutura - a hospedagem tem apenas o Django. Dizem que funciona Instagram, Pinterest, Bitbucket e Mozilla. Talvez seja por isso que a hospedagem o ofereça.

Por que VKontakte, não Telegram ou Viber?


Para passar do simples para o complexo, era importante encontrar a maneira mais fácil e intuitiva de configurar um webhook. O VKontakte acabou sendo o mais compreensível para mim, devido à clara ajuda e facilidade de conexão do webhook no painel de controle da comunidade na seção "Gerenciamento - Trabalhando com API". Uma descrição de como eu configurei e conectei tudo será ainda mais. No futuro, quero disponibilizar meu bot no Viber. Mas com o Telegram, ainda não está a caminho, porque minha hospedagem está na Rússia e o Telegram está bloqueado da Rússia. Para evitar problemas com o Telegram, você pode comprar hospedagem no exterior.

Como instalar o webhook for VK bot?


Nome de domínio https: // . Primeiro, você precisa registrar o nome de domínio do site e obter um certificado SSL.

Como não queria usar o domínio raiz para o chatbot, depois de registrar o domínio, criei um subdomínio e recebi um certificado SSL para ele.

Fiz todas essas manipulações no site de hospedagem em minha conta pessoal.
Como resultado, recebi o endereço do site mybot.mysite.ru e o certificado ssl.

Obtemos a chave VK (token) para o bot. Primeiro, criei um grupo fechado e depois entrei no "gerenciamento" do grupo, na seção "Trabalhando com API". Na guia "Teclas de acesso", há um token e, na guia "API de retorno de chamada", configurações de webhook.



Instale e configure o Django . Talvez você não precise do Django para executar seu script python, mas não sei o contrário.

Usando o PuTTY, conectei-me ao servidor via SSH, configurei e ativei o ambiente virtual.

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

o comando na primeira linha cria um ambiente virtual e o comando na segunda linha o ativa (observe o espaço após o período). A versão 2.7 é ditada pela hospedagem e pode diferir no seu caso. Portanto, leia a ajuda de hospedagem.

Próximo Django instalado
SSH:
 pip install 'django<2' 

Eu instalei a versão do Django não antes da segunda, porque o python 2.7 é usado na hospedagem e apenas a versão do Django com menos de 2 funciona com ele.

E instalou o módulo python para trabalhar com a API VKontakte
SSH:
 pip install vk 


FTP:
Criou uma pasta para django-projects no diretório raiz da hospedagem. Ele a chamou de django.

SSH:
Criou um novo projeto.
 cd django/ django-admin.py startproject mybot 

como resultado, uma pasta com o nome do projeto será criada (no nosso caso, é "mybot") na pasta / django. Ele conterá os arquivos iniciais do projeto criados automaticamente:
/ django
/ mybot - pasta do projeto
/ mybot - módulo com as configurações do nosso projeto
__init__.py
settings.py
urls.py
wsgi.py
manage.py

Um projeto no Django é um grupo de aplicativos. Uma aplicação no Django é um programa que executa as ações estabelecidas pelo desenvolvedor.

SSH:
Criou um aplicativo.
 cd mybot python manage.py startapp vk_bot 

Eu fui para a pasta / django / mybot e criei um novo aplicativo chamado "vk_bot".
Uma pasta com o nome do aplicativo foi criada na pasta do projeto que contém os arquivos do aplicativo criados automaticamente:

/ django
/ mybot - pasta do projeto
/ mybot - módulo com as configurações do nosso projeto
__init__.py
settings.py
urls.py
wsgi.py
manage.py
/ vk_bot - pasta do aplicativo
__init__.py
admin.py
apps.py
models.py
tests.py
views.py

FTP:
Eu baixei todos os arquivos do projeto no meu laptop para trabalhar com código.
Para trabalhar com arquivos de projeto e programação, usei o aplicativo Atom.

Atom:
Editou as configurações do projeto no arquivo /django/mybot/mybot/settings.py
 ... DEBUG = False ... ALLOWED_HOSTS = [ u'mybot.mysite.ru', ] ... 

Atom:
Configurações de roteamento de URL editadas no arquivo /django/mybot/mybot/urls.py
 ... urlpatterns = [ url(r'^vk_bot/', include('vk_bot.urls')), ] ... 

FTP:
Criou um arquivo /django/mybot/vk_bot/urls.py com o seguinte conteúdo:
 from django.conf.urls import url from . import views app_name = 'vk_bot' urlpatterns = [ url(r'^$', views.index, name='index'), ] 

Atom:
Editou o arquivo /django/mybot/vk_bot/views.py - adicionou uma função chamada index a ele que será executada quando o endereço for solicitado no 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 :)') 

No script views.py , na função index (request) , tive que desativar a proteção incorporada no Django CSRF, porque Eu estava recebendo o erro "403 Proibido". CSRF - Proteção de falsificação de solicitação entre sites - proteção contra falsificação de solicitação entre sites. Como o CSRF funciona, você pode ler neste artigo .
Para desativar a proteção, usei o decorador @csrf_exempt . Mas, para fornecer essa proteção da mesma forma, mas de uma maneira mais simples, usei uma chave secreta, registrada na seção de gerenciamento de grupo no site da VKontakte.

Esse código é responsável pelo processamento de solicitações do servidor que ele enviará para conectar nosso webhook ao processamento de eventos. Vamos apenas dizer "confirmação" do nosso 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) 

Observe que eu mantenho todas as configurações em um arquivo de configuração bot separado bot_config.py e, portanto, conecto-o no início do 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 = '...' 

E neste pedaço de código processa as mensagens do usuário:
 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) 

Se algo pareceu incompreensível, você também pode ler o artigo sobre a primeira instalação do Django .

A mágica para o servidor web . Para configurar o endereçamento de solicitações ao servidor da web, fui ao servidor na pasta com domínios através do cliente FTP FileZilla e criei a pasta " mybot.mysite.ru " lá, coloque três arquivos nele, cujo conteúdo foi retirado da ajuda na hospedagem:

.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() 

Aqui "myEnv" é o nome do ambiente virtual que você criou, "django" é a pasta na seção raiz do sistema de arquivos na hospedagem, "mybot" é o nome do projeto que criamos usando o Django.

index.html
    

"Vincule" nosso webhook ao processamento de mensagens no grupo VKontakte criado.
Para fazer isso, retornaremos à seção para gerenciar nosso grupo no site do VKontakte (veja a captura de tela acima). Vamos inserir nosso endereço de webhook no campo "Endereço"
  https://mybot.mysite.ru/vk_bot/ 
e clique no botão "Confirmar". Se nossa função de índice (solicitação) , escrita no arquivo /django/mybot/vk_bot/views.py, funcionar corretamente, ou seja, não contém erros de digitação e erros, uma marca de seleção verde aparecerá, simbolizando que está tudo bem.

Para que nosso webhook receba mensagens do servidor VKontakte sobre novas mensagens de usuário, na seção para gerenciar nosso grupo no site do VKontakte, na guia "Tipos de eventos", marque a caixa "Mensagens recebidas".

Como resultado, nosso script receberá essas mensagens no 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"} 

Observe que há um campo "secreto" na mensagem json . Essa é a mesma chave secreta que eu registrei na seção de gerenciamento de grupo do site do VKontakte, em vez da proteção incorporada no Django CSRF, que eu tive que desativar.

Como tornar um bot mais inteligente e melhor?


Você pode criar um banco de dados com respostas ao usuário e ensinar o bot a escolher a resposta com o significado mais próximo da pergunta do usuário. Vou falar sobre isso em outro artigo.
É possível e necessário programar cenários de interação do usuário, por assim dizer, para manter uma conversa.

Boa sorte no seu trabalho criativo!

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


All Articles