ãã£ãããããã®äœæã«é¢ããå¥ã®èšäºãå¿ èŠãªçç±
æ€çŽ¢ãäžååã ã£ãã®ãããããŸãããããã·ã¢ã®äŒç€Ÿããã¹ãããŠããDjangoãã¬ãŒã ã¯ãŒã¯ãšwebhookã¢ãããŒãã䜿çšããpythonãããã®äœæã«é¢ãã詳现ãªã¬ã€ããèŠã€ãããŸããã§ããã ã»ãšãã©ã®è³æã§ã¯ãFlaskãã¬ãŒã ã¯ãŒã¯ã®äœ¿çšãšãHerokuããã³PythonAnywhereã®ç¡æãã¹ãã£ã³ã°ã®äœ¿çšã«ã€ããŠèª¬æããŠããŸãã Habrã³ãã¥ããã£ã®çµéšã¯ç§ãå©ããŠãããã®ã§ãæè¬ã®ããããšããŠããã®èšäºã®å·çã«æéãè²»ããããšã«ããŸããã ããã«èå³ã®ãããã¹ãŠã®äººãæéãç¯çŽããwebhookã¢ãããŒãã䜿çšããŠãã¹ãã£ã³ã°ã§Djangoãã¬ãŒã ã¯ãŒã¯ã䜿çšããŠPythonããããäœæããæ¹æ³ãããããç解ã§ããããã«ããããã«åŸãããå®éã®çµéšã«ã€ããŠèª¬æããŸãã
ãªããã¹ãã£ã³ã°ãæ¯æã£ãã®ã§ããïŒ
ç§ã®æèŠã§ã¯ãå®è¡å¯èœãªããŒãžã§ã³ã®ãããã¯ãããŒã«ã«ã³ã³ãã¥ãŒã¿ãŒããç¬ç«ããŠããã24æé365æ¥å©çšå¯èœã§ãã ãããè¡ãã«ã¯ãWebãµãŒããŒãããŒã¿ããŒã¹ç®¡çã·ã¹ãã ïŒãããã®æ©èœãéçºããããïŒããã¡ã€ã³åã®ç»é²ãSSL蚌ææžã®ååŸãããã³ãã®ãã¹ãŠã®çµæžã«å¯Ÿããæè¡ãµããŒãããããã¹ãã£ã³ã°ãå¿ èŠã§ãã ãã®ãããªãµãŒãã¹ã«ã¯ãéãããããŸãã ããããæ©èœããããã®ã€ã³ãã©ã¹ãã©ã¯ãã£ãç¶æããããã«ã1ãæããã138ã«ãŒãã«ãæ¯æããŸããPython+ Djangoã®ãµããŒããMySQL DBMS 25 GBãSSHã®ãµããŒãã§ãã
ã»ãšãã©ã®ã¬ãã¹ã³ã§ãããŒãœãã«ã³ã³ãã¥ãŒã¿ãŒãå€åæéãªã©ã«å¶éã®ãããµãŒããŒãŸãã¯ç¡æãã¹ãã£ã³ã°ãšããŠäœ¿çšãããããšã確èªããŸãããäŸã§ã¯ããããã¯ãŠãŒã¶ãŒããã®æ°ããã¡ãã»ãŒãžããªããã¡ãã»ã³ãžã£ãŒãµãŒããŒãå®æçã«ããŒãªã³ã°ããŸãã ããã¯ã¡ãã»ã³ãžã£ãŒãµãŒããŒã«äœåãªè² è·ããããããããã°ããã®éãããããçŠæ¢ãã§ããŸãã ç§ã®æèŠã§ã¯ãããã¯ãã¹ãŠçç£çãªäœ¿çšã«ã¯äžå¯æ¬ ã§ã¯ãããŸããã ãããããã¹ããšãã¬ãŒãã³ã°ã«ã€ããŠã¯éåžžã«å¯èœã§ãã
webhookãšã¯äœã§ããããªãã§ããïŒ
補åã«ã€ããŠã¯ããŠã§ãããã¯ã䜿çšããæ£ãã決å®ãã€ãŸããã¡ãã»ã³ãžã£ãŒãµãŒããŒããã®ã¡ãã»ãŒãžãããããæåŸ ããå®æçãªèŠæ±ã§ããã³ããŒãããããªãã¢ãããŒããæ€èšããŸããæ°ããã¡ãã»ãŒãžããããã©ããã ãŠã§ãããã¯ã䜿çšãããšã次ã®ããã«ãªããŸãããŠãŒã¶ãŒãã¡ãã»ãŒãžãäœæããã¡ãã»ã³ãžã£ãŒãµãŒããŒãããããããã«éä¿¡ããã¡ãã»ãŒãžãåä¿¡ããŠââåŠçããå¿çããŸããã
ãªããžã£ã³ãŽ
pythonã§ããããäœæããããšã«ããã®ã§ããã¹ãã£ã³ã°ã§pythonãµããŒããæ¥ç¶ããŸããã ãããããã¬ãŒã ã¯ãŒã¯ãéžæããããšã¯ã§ããŸããã§ããããã¹ãã£ã³ã°ã«ã¯DjangoãããããŸããã 圌ãã¯ãInstagramãPinterestãBitbucketãMozillaã§æ©èœãããšèšã£ãŠããŸãã ããããããããã¹ãã£ã³ã°ããããæäŸããçç±ã§ãã
ãªãTelegramãViberã§ã¯ãªãVKontakteãªã®ã§ããïŒ
åçŽãªãã®ããè€éãªãã®ã«ç§»è¡ããããã«ããŠã§ãããã¯ãã»ããã¢ããããæãç°¡åã§çŽæçãªæ¹æ³ãèŠã€ããããšãéèŠã§ããã VKontakteã¯ãã管ç-APIã®æäœãã»ã¯ã·ã§ã³ã®ã³ãã¥ããã£ã³ã³ãããŒã«ããã«ã§æ確ãªãã«ããšwebhookã®æ¥ç¶ãç°¡åã ã£ããããç§ã«ãšã£ãŠæãç解ããããããšãããããŸããã ãã¹ãŠãã©ã®ããã«æ§æããŠæ¥ç¶ãããã«ã€ããŠã®èª¬æã¯ããã«ç¶ããŸãã å°æ¥çã«ã¯ãViberã§ããããå©çšã§ããããã«ããŸãã ãããŠãç§ã®ãã¹ãã£ã³ã°ã¯ãã·ã¢ã«ããããã¬ã°ã©ã ã¯ãã·ã¢ãããããã¯ãããŠããã®ã§ãTelegramã¯ãŸã é²è¡äžã§ãã Telegramã®åé¡ãåé¿ããããã«ãæµ·å€ã§ãã¹ãã£ã³ã°ãè³Œå ¥ã§ããŸãã
VKãããã«webhookãã€ã³ã¹ããŒã«ããæ¹æ³ã¯ïŒ
ãã¡ã€ã³åhttpsïŒ// ã æåã«ããµã€ãã®ãã¡ã€ã³åãç»é²ãããã®SSL蚌ææžãååŸããå¿ èŠããããŸãã
ãã£ãããããã«ã«ãŒããã¡ã€ã³ã䜿çšããããªãã£ãããããã¡ã€ã³ãç»é²ããåŸããµããã¡ã€ã³ãäœæããSSL蚌ææžãåãåããŸããã
ããããã¹ãŠã®æäœã¯ãå人ã¢ã«ãŠã³ãã®ãã¹ãã£ã³ã°ãµã€ãã§è¡ããŸããã
ãã®çµæããµã€ãmybot.mysite.ruã®ã¢ãã¬ã¹ãšSSL蚌ææžãåãåããŸããã
ãããVKontakteã®ã¢ã¯ã»ã¹ããŒïŒããŒã¯ã³ïŒãååŸããŸãã æåã«éããã°ã«ãŒããäœæãã次ã«ãAPIã®æäœãã»ã¯ã·ã§ã³ã§ã°ã«ãŒãã®ã管çãã«å ¥ããŸããã [ã¢ã¯ã»ã¹ããŒ]ã¿ãã«ã¯ããŒã¯ã³ãããã[ã³ãŒã«ããã¯API]ã¿ãã«ã¯Webhookèšå®ããããŸãã

Djangoãã€ã³ã¹ããŒã«ããŠèšå®ããŸã ã pythonã¹ã¯ãªãããå®è¡ããã®ã«Djangoã¯å¿ èŠãªããããããŸãããããã以å€ã®æ¹æ³ã¯ããããŸããã
PuTTYã䜿çšããŠãSSHçµç±ã§ãµãŒããŒã«æ¥ç¶ããä»®æ³ç°å¢ãæ§æããŠã¢ã¯ãã£ãåããŸããã
SSHïŒ
virtualenv-2.7 virtualenv/myEnv . virtualenv/myEnv/bin/activate
æåã®è¡ã®ã³ãã³ãã¯ä»®æ³ç°å¢ãäœæãã2è¡ç®ã®ã³ãã³ãã¯ãããã¢ã¯ãã£ãã«ããŸãïŒããªãªãã®åŸã®ã¹ããŒã¹ã«æ³šæããŠãã ããïŒã ããŒãžã§ã³2.7ã¯ãã¹ãã£ã³ã°äºæ¥è ã«ãã£ãŠæ±ºå®ãããå Žåã«ãã£ãŠã¯ç°ãªãå ŽåããããŸãã ãããã£ãŠããã¹ãã£ã³ã°ãã«ãããèªã¿ãã ããã
次ã«ã€ã³ã¹ããŒã«ãããDjango
SSHïŒ
pip install 'django<2'
ãã¹ãã£ã³ã°ã§ã¯python 2.7ã䜿çšãããŠããã2æªæºã®ããŒãžã§ã³ã®Djangoã®ã¿ãåäœãããããDjangoããŒãžã§ã³ã2çªç®ãããåã«ã€ã³ã¹ããŒã«ããŸããã
VK APIã§åäœããããã«Pythonã¢ãžã¥ãŒã«ãã€ã³ã¹ããŒã«ããŸãã
SSHïŒ
pip install vk
FTPïŒ
ãã¹ãã£ã³ã°ã®ã«ãŒããã£ã¬ã¯ããªã«django-projectsã®ãã©ã«ããŒãäœæããŸããã 圌ã¯åœŒå¥³ã®ãžã£ã³ãŽãåŒãã ã
SSHïŒ
æ°ãããããžã§ã¯ããäœæããŸããã
cd django/ django-admin.py startproject mybot
ãã®çµæã/ djangoãã©ã«ããŒã«ãããžã§ã¯ãã®ååã®ãã©ã«ããŒïŒãã®å Žåã¯ãmybotãïŒãäœæãããŸãã èªåçã«äœæãããåæãããžã§ã¯ããã¡ã€ã«ãå«ãŸããŸãã
/ãžã£ã³ãŽ
/ 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ããšããæ°ããã¢ããªã±ãŒã·ã§ã³ãäœæããŸããã
ã¢ããªã±ãŒã·ã§ã³ã®ååãæã€ãã©ã«ããŒããèªåçã«äœæãããã¢ããªã±ãŒã·ã§ã³ãã¡ã€ã«ãå«ããããžã§ã¯ããã©ã«ããŒã«äœæãããŸããã
/ãžã£ã³ãŽ
/ 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ïŒ
ã³ãŒããæäœããããã«ããã¹ãŠã®ãããžã§ã¯ããã¡ã€ã«ãã©ãããããã«ããŠã³ããŒãããŸããã
ãããžã§ã¯ããã¡ã€ã«ãšããã°ã©ãã³ã°ãæäœããããã«ã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ã¹ã¯ãªããã®ã€ã³ããã¯ã¹ïŒèŠæ±ïŒé¢æ°ã§ãDjango CSRFã«çµã¿èŸŒãŸããŠããä¿è·ãç¡å¹ã«ããå¿ èŠããããŸããã ã403 Forbiddenããšã©ãŒã衚瀺ãããŸããã CSRF-ã¯ãã¹ãµã€ããªã¯ãšã¹ããã©ãŒãžã§ãªä¿è·-ã¯ãã¹ãµã€ããªã¯ãšã¹ããã©ãŒãžã§ãªã«å¯Ÿããä¿è·ã CSRFã®ä»çµã¿ã«ã€ããŠã¯ããã®èšäºãåç §ããŠãã ãã ã
ä¿è·ãç¡å¹ã«ããããã«ã @ csrf_exemptãã³ã¬ãŒã¿ãŒã䜿çšããŸãã ã ãããããã®ä¿è·ããã¹ãŠåãããã«ãããç°¡åãªæ¹æ³ã§æäŸããããã«ãVKontakte Webãµã€ãã®ã°ã«ãŒã管çã»ã¯ã·ã§ã³ã«ç»é²ãããŠããç§å¯ããŒã䜿çšããŸããã
ãã®ã³ãŒãã¯ãã€ãã³ãåŠçã®ããã«webhookãæ¥ç¶ããããã«éä¿¡ãããµãŒããŒããã®ãªã¯ãšã¹ããåŠçããŸãã 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_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 ããäœæãããã®äžã«3ã€ã®ãã¡ã€ã«ãå ¥ããŸãã
.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
äœæãããVKontakteã°ã«ãŒãã§ãWebhookãã¡ãã»ãŒãžåŠçã«ããã€ã³ããããŸãã
ãããè¡ãã«ã¯ãVKontakte Webãµã€ãã®ã°ã«ãŒãã®ç®¡çã»ã¯ã·ã§ã³ã«æ»ããŸãïŒäžã®ã¹ã¯ãªãŒã³ã·ã§ãããåç §ïŒã ãã¢ãã¬ã¹ããã£ãŒã«ãã«webhookã¢ãã¬ã¹ãå ¥åããŸããã
https://mybot.mysite.ru/vk_bot/[確èª]ãã¿ã³ãã¯ãªãã¯ããŸãã /django/mybot/vk_bot/views.pyãã¡ã€ã«ã«èšè¿°ãããã€ã³ããã¯ã¹ïŒãªã¯ãšã¹ãïŒé¢æ°ãæ£ããæ©èœããå Žåãã€ãŸãã¿ã€ããã¹ããšã©ãŒãå«ãŸããŠããªãå Žåããã¹ãŠãæ£åžžã§ããããšã瀺ãç·è²ã®ãã§ãã¯ããŒã¯ã衚瀺ãããŸãã
WebhookãVKontakteãµãŒããŒããæ°ãããŠãŒã¶ãŒã¡ãã»ãŒãžã«é¢ããã¡ãã»ãŒãžãåä¿¡ããã«ã¯ãVKontakte Webãµã€ãã®ã°ã«ãŒãã管çããã»ã¯ã·ã§ã³ã®[ã€ãã³ãã¿ã€ã]ã¿ãã§ã[åä¿¡ã¡ãã»ãŒãž]ããã¯ã¹ããªã³ã«ããŸãã
ãã®çµæãã¹ã¯ãªããã¯ãããã®ã¡ãã»ãŒãžã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ã¡ãã»ãŒãžã«ã¯ãç§å¯ããã£ãŒã«ããããããšã«æ³šæããŠãã ããã ããã¯ãç¡å¹ã«ããå¿ èŠããã£ãDjango CSRFã«çµã¿èŸŒãŸããŠããä¿è·ã®ä»£ããã«ãVKontakteã®ã°ã«ãŒã管çã»ã¯ã·ã§ã³ã§ç»é²ããã®ãšåãç§å¯ããŒã§ãã
ããããããè³¢ããããè¯ãããæ¹æ³ã¯ïŒ
ãŠãŒã¶ãŒãžã®åçãå«ãããŒã¿ããŒã¹ãäœæãããŠãŒã¶ãŒã®è³ªåã«æãæå³ã®ããåçãéžæãããããããã«æããããšãã§ããŸãã ããã«ã€ããŠã¯å¥ã®èšäºã§èª¬æããŸãã
äŒè©±ãç¶æããããã«ãããã°ãŠãŒã¶ãŒã€ã³ã¿ã©ã¯ã·ã§ã³ã·ããªãªãããã°ã©ã ããããšãå¯èœã§ãããå¿ èŠã§ãã
ããªãã®åµé çãªä»äºã§é 匵ã£ãŠãã ããïŒ