如何使用Python,Django和Webhook为VKontakte创建聊天机器人

为什么还要再写一篇有关创建聊天机器人的文章?


也许我搜索不力,但是找不到关于使用Django框架和由俄罗斯公司托管的webhook方法创建python机器人的详细指南。 大多数材料都谈论使用Flask框架以及使用Heroku和PythonAnywhere的免费托管。 Habr社区的经验帮了我大忙,所以我决定抽出宝贵的时间写这篇文章。 我将描述获得的实践经验,以使对此感兴趣的每个人都可以节省时间,并更好地了解如何在使用webhook方法的主机上使用Django框架在Python中制作机器人。

为什么要付费托管?


我认为,可行的bot版本是它独立于您的本地计算机并且24/7可用。 为此,您需要一个主机,上面有一个主机:Web服务器,数据库管理系统(用于开发Bot的功能),域名注册,为此获取SSL证书以及对所有上述经济情况的技术支持。 这种服务要花钱。 我每月为托管138卢布支付托管费用,以维护该机器人的工作基础:支持Python + Django,25 GB的MySQL DBMS,支持SSH。
在大多数课程中,我看到个人计算机被用作服务器或免费主机,但工作时间受到限制等。在示例中,该机器人会定期轮询Messenger服务器,以查找来自用户的新消息。 这是Messenger服务器上的额外负载,因此可以在一段时间内“禁止”该漫游器。 我认为,所有这些对于生产性使用都不是至关重要的。 但是对于测试和培训是完全可能的。

什么是网络挂钩,为什么?


对于产品,我认为正确的决定是使用Webhook,即我们的机器人在这种方法中,期望机器人从Messenger服务器获取消息,而不用定期请求“锤击”消息:是否有新消息。 有了一个Webhook,将是这样的:用户编写了一条消息,Messenger服务器将其发送到您的机器人,他收到了该消息,对其进行了处理并进行了回答。

为什么是Django


我决定用python做一个机器人,所以我在主机上连接了python支持。 但是我没有一个选择的框架-托管只有Django。 他们说它适用于Instagram,Pinterest,Bitbucket和Mozilla。 也许这就是为什么托管提供它的原因。

为什么选择VKontakte,而不是Telegram或Viber?


从简单到复杂,对我来说,找到一种最简单,最直观的方式来建立一个Webhook至关重要。 事实证明,对于我来说,VKontakte是最可理解的,因为在“管理-使用API​​”部分的社区控制面板中,连接Webhook的明确帮助和便捷性。 我将如何进一步配置和连接所有内容的描述。 将来,我想让我的机器人在Viber中可用。 而且Telegram不在路上,因为我的托管地点在俄罗斯,而Telegram被俄罗斯封锁了。 为避免Telegram出现问题,您可以在国外购买托管服务。

如何为VK bot安装webhook?


域名https:// 。 首先,您需要注册该站点的域名并为其获取ssl证书。

我不想使用聊天机器人的根域,因此在注册该域之后,我创建了一个子域并收到了ssl证书。

我用我的个人帐户在托管站点上进行了所有这些操作。
结果,我收到了网站mybot.mysite.ru的地址及其ssl证书。

我们获得了机器人的VK密钥(令牌)。 首先,我创建了一个封闭的组,然后在“使用API​​”部分中进入该组的“管理”。 在“访问密钥”选项卡中是令牌,在“回调API”选项卡中是Webhook设置。



安装和配置Django 。 也许您不需要Django来运行python脚本,但是我不知道如何做。

使用PuTTY,我通过SSH连接到服务器,配置并激活了虚拟环境。

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

第一行中的命令创建一个虚拟环境,第二行中的命令将其激活(注意句点后的空格)。 2.7版由托管服务商决定,您的情况可能有所不同。 因此,请阅读托管帮助。

接下来安装Django
SSH:
 pip install 'django<2' 

我安装的Django版本不早于第二个版本,因为在主机上使用了python 2.7,并且只有小于2的Django版本可以使用。

并安装了python模块以与VKontakte API配合使用
SSH:
 pip install vk 


FTP:
在主机的根目录中为django-projects创建了一个文件夹。 他称她为django。

SSH:
创建了一个新项目。
 cd django/ django-admin.py startproject mybot 

结果,将在/ django文件夹中创建一个带有项目名称的文件夹(在我们的示例中为“ mybot”)。 它将包含自动创建的初始项目文件:
/ 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
管理员
apps.py
models.py
tests.py
views.py

FTP:
我将所有项目文件下载到笔记本电脑上以使用代码。
为了处理项目文件和编程,我使用了Atom应用程序。

原子:
在文件/django/mybot/mybot/settings.py中编辑了项目设置
 ... DEBUG = False ... ALLOWED_HOSTS = [ u'mybot.mysite.ru', ] ... 

原子:
/django/mybot/mybot/urls.py文件中编辑的URL路由设置
 ... 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'), ] 

原子:
编辑文件/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-跨站点请求伪造保护-防止跨站点请求伪造。 您可以在本文中阅读CSRF的工作方式。
要禁用保护,我使用了@csrf_exempt装饰器。 但是为了提供相同的保护,但以一种更简单的方式,我使用了一个秘密密钥,该密钥已在VKontakte网站上的组管理部分中注册。

这段代码负责处理来自服务器的请求,服务器将发送该请求以连接我们的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) 

请注意,我将所有配置设置都保存在单独的bot配置文件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设置文章

Web服务器的魔力 。 为了配置对Web服务器的请求的寻址,我通过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“绑定”到创建的VKontakte组中的消息处理。
为此,我们将返回到VKontakte网站上用于管理组的部分(请参见上面的屏幕截图)。 我们将在“地址”字段中输入Webhook地址
  https://mybot.mysite.ru/vk_bot/ 
然后点击“确认”按钮。 如果我们在文件/django/mybot/vk_bot/views.py中编写的索引(请求)功能可以正常工作,也就是说,它不包含错别字和错误,则会出现一个绿色的选中标记,表示一切正常。

为了使我们的Webhook接收来自VKontakte服务器的有关新用户消息的消息,请在VKontakte网站上“管理我们的组”部分的“事件类型”选项卡中,选中“传入消息”框。

结果,我们的脚本将以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消息中有一个“秘密”字段。 这是我在VKontakte网站的组管理部分中注册的同一密钥,而不是我必须禁用的Django CSRF中内置的保护。

如何使机器人更聪明更好?


您可以创建一个包含用户答案的​​数据库,并让漫游器选择含义最接近用户问题的答案。 我将在另一篇文章中对此进行讨论。
可以这么说,对用户交互方案进行编程以保持对话是可能且必要的。

祝您创作愉快!

Source: https://habr.com/ru/post/zh-CN429628/


All Articles