Чат-бот для ВК на Python, Django и Webhook

Чат-бот для ВК на Python, Django и Webhook

PythonGuru

Привет, любитель Python!

В сегодняшней статье мы напишем чат-бота в ВК на python с применением фреймворка Django и подхода webhook, работающего русском на хостинге.


Почему платный хостинг?

Жизнеспособный вариант бота — это когда он не зависит от вашего локального компьютера и всегда доступен. Для этого нужен хостинг, на котором есть: веб-сервер, система управления БД, регистрация домена, SSL-сертификат для него и желательно техническая поддержка. Такие услуги стоят небольших денег. Это стоит в пределах 100-200руб в месяц за поддержание инфраструктуры для работоспособности бота: поддержка Python + Django, СУБД MySQL 25 Гб, поддержка SSH.

Но в большинстве случаев используется персональный компьютер в качестве сервера или бесплатный хостинг с ограничениями по времени работы и т. д. В таком случает бот с периодичностью опрашивает сервер вконтакте на предмет появления новых сообщений от пользователей. Это лишняя нагрузка на серверы самого вк, поэтому бот могут забанить на какое-то время. Всё это по моему мнению не жизненно для продуктивного использования. Но для теста и обучения вполне реально.

Что же такое webhook и зачем он нам?

Для продуктивности правильным решением считаем использование webhook’а, т. е. подхода, при котором наш бот ожидает сообщений от сервера вк, а не посылает ему периодически запросы - есть новые сообщения или нет. С webhook’ом - так: написал пользователь сообщение, сервер мессенджера отправил его вашему боту, он сообщение принял, обработал и ответил.

Почему Django?

Мы будем делать бота на python, поэтому надо подключить на хостинге поддержку python. Но выбора фреймворка нет — хостинг располагает только Django.

Устанавливаем webhook для бота ВКонтакте

Доменное имя https:// - SSL-сертификат

Для начала нужно зарегистрировать доменное имя сайта и получить для него ssl-сертификат.

Мы не будем использовать для чат-бота корневой домен, поэтому после регистрации домена, мы создали поддомен и получили для него ssl-сертификат.

Все эти манипуляции мы сделали на сайте хостинга в личном кабинете.

В итоге мы имеем адрес сайта mybot.my-site.ru и ssl к нему.

Получаем для бота токен от ВКонтакте

Сперва создаём закрытую группу, далее в «управление» группой, в раздел «Работа с API». Во вкладке «Ключи доступа» находится токен, а во вкладке «Callback API» настройки webhook’a.

Установка и настройка Django

Возможно что для запуска вашего скрипта на python Django не нужен.

Используя PuTTY мы подключились к серверу по SSH, настроили и активировали виртуальное окружение.

SSH:

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

Команда из первой строке создаёт само виртуальное окружение, а команда во второй — его активирует (обратите внимание на пробел после точки). Версия 2.7 по умолчанию используется нашим хостингом и может отличаться в вашем случае. Поэтому читайте справку своего хостинга.

Далее устанавливаем Django

SSH:

pip install ‘django<2’

Устанавливаем Джанго версии не ранее второй, так как на хостинге используется python 2.7, а с ним работает только Django версии меньше 2

И устанавливаем python модуль для работы с API ВК

SSH:

pip install vk


FTP:

Создаём папку для django-проектов в корневой директории на хостинге. Называем её например django.

SSH:

Создём новый проект.

cd django/
django-admin.py startproject mybot

В результате будет создана папка с именем проекта (в нашем случае — это «mybot») в папке /django. В ней будут файлы начального проекта, созданные автоматически:

/django

 /mybot – папка проекта

  /mybot – модуль с настройками нашего проекта

    __init__.py

     settings.py

     urls.py

     wsgi.py

  manage.py

Проект в Django – это группа приложений. Приложение в Django – это программа, которая выполняет действия, заложенные разработчиком.


SSH:

Создаём приложение.

cd mybot
python manage.py startapp vk_bot

Далее переходим в папку /django/mybot и создаём новое приложение с именем «vk_bot».

В папке проекта создалась папка с именем приложения, содержащая файлы приложения, созданные автоматически:

/django

 /mybot – папка проекта

  /mybot – модуль с настройками нашего проекта

     __init__.py

     settings.py

     urls.py

     wsgi.py

  manage.py

  /vk_bot – папка приложения

     __init__.py

     admin.py

     apps.py

     models.py

     tests.py

     views.py


FTP:

Мы загрузили все файлы проекта на свой компьютер для удобной работы с кодом.

Для работы с файлами проекта и программирования мы использовал приложение Sublime Text 3.


Sublime Text 3:

Редактируем настройки проекта в файле /django/mybot/mybot/settings.py

...
DEBUG = False
...
ALLOWED_HOSTS = [
    u'mybot.mysite.ru',
]
...

Sublime Text 3:

Отредактировали настройки url-маршрутизации адресов в файле /django/mybot/mybot/urls.py

...
urlpatterns = [
    url(r'^vk_bot/', include('vk_bot.urls')),
]
...

FTP:

Создали файл /django/mybot/vk_bot/urls.py такого содержания:

from django.conf.urls import url

from . import views

app_name = 'vk_bot'

urlpatterns = [
    url(r'^$', views.index, name='index'),
]

Sublime Text 3:

Отредактировал файл /django/mybot/vk_bot/views.py – добавили в него функцию под названием index, которая будет выполняться при запросе в браузере адреса

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 :)')

В скрипте views.py, в функции index(request) пришлось отключить встроенную в Django CSRF защиту, так как получалась ошибка «403 Forbidden». CSRF — Cross Site Request Forgery protection — защита от подделки межсайтовых запросов.

Для отключения защиты мы использовали декоратор @csrf_exempt. Но чтобы все таки эту защиту обеспечить, но более простым способом мы использовали секретный ключ, который прописывается в разделе управления группой на сайте ВК.

Вот этот кусок кода отвечает за то, чтобы обрабатывать запросы с сервера, которые он будет посылать для того, чтобы подключить наш webhook для обработки событий. Скажем так, подтверждение нашего webhook’a.

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)

Обратите внимание, что все конфигурационные настройки мы держим в отдельном файле конфигурации бота bot_config.py и поэтому подключаем его в начале скрипта:

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 = '...'

А в этот код обрабатывает сообщения пользователей:

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)

Если что-то показалось непонятным, можно дополнительно прочитать статью о первой настройке Django.

Для настройки адресации запросов к веб-серверу заходим на сервер в папку с доменами через FTP-клиент FileZilla и создаём там папку mybot.mysite.ru , в неё ложем три файла, содержимое которых взято из справки на хостинге:

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

Здесь «myEnv» — название созданного вами виртуального окружения, «django» — папка в корневом разделе файловой системы на хостинге, «mybot» — название проекта, который мы создали с помощью Django.

index.html

Сайт в разработке

Привязываем наш webhook к обработке сообщений в созданной группе ВК.

Для этого вернёмся в раздел управления нашей группой на сайте ВКонтакте (см. скриншот выше). Введём в поле «Адрес» наш адрес webhook’ahttps://mybot.my-site.ru/vk_bot/

и нажмём кнопку «Подтвердить». Если наша функция index(request), написанная в файле /django/mybot/vk_bot/views.py работает корректно, то есть в ней нет опечаток и ошибок, то появится зелёная галочка, символизирующая что всё хорошо.

Чтобы наш webhook получал от сервера ВКонтакте сообщения о новых сообщениях пользователей, в разделе управления нашей группой на сайте ВКонтакте, во вкладке «Типы событий» поставим галочку напротив «входящие сообщения».

В итоге наш скрипт будет получать вот такие сообщения в 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"}


Обратите внимание на то, что в json сообщении есть поле «secret». Это тот самый секретный ключ, который мы прописали в разделе управления группой на сайте ВКонтакте, взамен встроенной в Django CSRF защиты, которую нам пришлось отключить.

Как сделать бота лучше?

Можно создать базу данных с ответами пользователю и научить бота выбирать ответ наиболее близкий по смыслу к вопросу пользователя.

Можно запрограммировать сценарии взаимодействия с пользователем, так сказать чтобы поддержать разговор.


Совершенствуй знания по Python каждый день у нас на канале, PythonGuru.

Вопросы, реклама - @pythonguru_admin

Поддержать проект (сбербанк):

4817760113082329

Report Page