ローカルでも動くSlackBot管理ツールができるまで 〜 WebUI編 1 〜
今回から何回かに分けて、はてブから情報を取得しSlackに投稿するBOTを管理するツールを作成していく。
今までにこのブログ内で紹介しgithubにあげているソースを利用する。
[amazonjs asin="B009Z30HPG" locale="JP" title="Dive Into Python 3 日本語版"]
完成形
[雑][Python] ローカルでも動くSlackのBot管理ツールを作成してみた(Bottle + jinja2 + Slacker)
構成
開発環境
今回はローカル(MacBookAir)で開発してみた。
brewでpython3をインストールしている前提とする。
[shell]
$ sudo brew install python3
[/shell]
データベースはローカルであることとPython標準ライブラリとして入っているため、
sqlite3で構築する。
venvで仮想環境を構築する
pyvenvで仮想環境を構築し、pipをアップデートしておく。
[shell]
$ cd ~/Documents
$ pyvenv slack_botter
$ cd slack_botter
$ source bin/activate
(slack_botter)$ pip install –upgrade pip
[/shell]
githubから必要なファイルを取得する
以前、Pythonフレームワーク bottle とテンプレートエンジン jinja2 で作ったものを利用するため、githubからダウンロードする。
ダウンロードしたものをsitesという名前にリネームしておく。
[shell]
(slack_botter)$ cd ~/Documents/slack_botter
(slack_botter)$ git clone https://github.com/umentu/bottle_jinja2
(slack_botter)$ mv bottle_jinja2 sites
[/shell]
pipで必要なライブラリをインストール
githubからダウンロードしたものの中にrequirements.txtが入っているため、pipで必要なライブラリをインストールする。
[shell]
(slack_botter)$ pip install -r ./sites/requirements.txt
[/shell]
sites/index.pyを実行し、ブラウザで https://localhost:8080/top/ にアクセスして表示できるかを確認してみる。
[shell]
(slack_botter)$ python sites/index.py
[/shell]
Slackのチャンネル名一覧を取得するため、gitからslackbotを取得
SlackBotを管理する際に、存在するチャンネル一覧を表示させたいため、Slackからチャンネル一覧を取得する。
これも以前作ったものを利用するため、
githubからダウンロードする。
今回はslack_bot.pyというファイルのみ必要なため、sites内に移動しておく。
また、requirements.txtがあるため、slackbot用に必要なライブラリをpipでインストールする。
以上が終わったらslackbotディレクトリは必要ないため、slackbotディレクトリを削除する。
[shell]
(slack_botter)$ cd ~/Documents/slack_botter
(slack_botter)$ git clone https://github.com/umentu/slackbot
(slack_botter)$ mv slackbot/slack_bot.py ./
(slack_botter)$ pip install -r slackbox/requirements.txt
(slack_botter)$ rm -rf ./slackbot
[/shell]
sqlite3 でデータベース作成
sqlite3のDBファイルを作成するために、slack_botterディレクトリ配下にdbディレクトリを作成しておく。
[shell]
(slack_botter)$ cd ~/Documents/slack_botter
(slack_botter)$ mkdir db
[/shell]
dbディレクトリ配下に、データベース・テーブル・テストデータを作成するためのcreate_db.pyファイルを作成する。
[python title="create_db.pyの内容"]
# -*- coding: utf-8 -*-
import os
import sqlite3
if __name__ == '__main__’:
# データベースアクセス
path = os.path.dirname( os.path.abspath(__file__))
connect = sqlite3.connect(path + "/hatena.db")
cursor = connect.cursor()
# テーブル作成
sql = """
CREATE TABLE hatebu_list (
id INTEGER PRIMARY KEY,
channel VARCHAR(128),
word TEXT,
bookmark_count INTEGER,
last_post TEXT
);
"""
# テーブル確認
cursor.execute(sql)
sql = """
SELECT * FROM sqlite_master;
"""
con = cursor.execute(sql)
for row in con:
print(row)
# テストデータ挿入
sql = """
INSERT INTO hatebu_list (
channel,
word,
bookmark_count,
last_post)
VALUES (
'test_channel’,
'test_word’,
100,
'2000-01-01T00:00:00+09:00’
);
"""
cursor.execute(sql)
# テストデータ確認
sql = """
SELECT * FROM hatebu_list;
"""
con = cursor.execute(sql)
for row in con:
print(row)
# 変更を更新する
connect.commit()
# データベースを閉じる
connect.close()
[/python]
実行すると、dbディレクトリ配下に hatena.db というDBファイルが作成される。
[shell]
(slack_botter)$ python db/create_db.py
('table’, 'hatebu_list’, 'hatebu_list’, 2, 'CREATE TABLE hatebu_list (
id INTEGER PRIMARY KEY,
channel VARCHAR(128),
word TEXT,
bookmark_count INTEGER,
last_post TEXT
)’)
(1, 'test_channel’, 'test_word’, 100, '2000-01-01T00:00:00+09:00’)
(slack_botter)$ ls -l ./db
total 16
-rw-r–r– 1 umentu staff 1236 6 16 23:39 create_db.py
-rw-r–r– 1 umentu staff 2048 6 16 23:40 hatena.db
[/shell]
UIを作成
(以降から若干置いてけぼり感が出てしまうかもしれないのですが。。。)
sitesディレクトリ配下にWebUIの本体となるsites.pyを作成する。
index.pyをコピーして作成すると楽。
[python title="sites.pyの内容"]
# -*- coding: utf-8 -*-
import os
import sys
import csv
# sqlite3をインポート
import sqlite3
# slack_botライブラリもインポート
sys.path.append( os.path.dirname(__file__) )
from slack_bot import Slack
from bottle import route, run
from bottle import TEMPLATE_PATH, jinja2_template as template
from bottle import static_file
from bottle import get, post, request, response
from bottle import redirect
# sites.pyが設置されているディレクトリの絶対パスを取得
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
# テンプレートファイルを設置するディレクトリのパスを指定
TEMPLATE_PATH.append(BASE_DIR + "/views")
@route('/css/<filename>’)
def server_css(filename):
""" setting for css file """
return static_file(filename, root=BASE_DIR+"/static/css")
@route('/js/<filename>’)
def server_js(filename):
""" setting for js file """
return static_file(filename, root=BASE_DIR+"/static/js")
@route('/img/<filename>’)
def server_img(filename):
""" setting for img file """
return static_file(filename, root=BASE_DIR+"/static/img")
@route('/font/<filename>’)
def server_font(filename):
""" setting for font file """
return static_file(filename, root=BASE_DIR+"/static/fonts")
@route('/hatebu’)
@route('/hatebu/’)
def hatebu():
return template('hatebu’)
if __name__ == "__main__":
run(host="localhost", port=8080, debug=True, reloader=True)
[/python]
sites/views 配下のtop.htmlをhatebu.htmlという名前でコピー
[shell]
(slack_botter)$ cp sites/views/top.html sites/views/hatebu.html
[/shell]
sites.pyを実行して、ブラウザでhttps://localhost:8080/hatebuにアクセスできるか確かめる。
アクセスできたら、sites/sites.py のhatebu関数を再度編集
[python title="sites.pyの内容"]
@route('/hatebu’)
@route('/hatebu/’)
def hatebu():
# データベースアクセス
path = os.path.dirname(os.path.dirname( os.path.abspath(__file__))) + "/db"
connect = sqlite3.connect(path + "/hatena.db")
cursor = connect.cursor()
# hatebu_list テーブルからデータを取得
sql = """
SELECT * FROM hatebu_list
"""
# 取得したデータをパースしてリストに保存
hatebu_list = []
con = cursor.execute(sql)
for row in con:
tmp_row = {}
for idx, col in enumerate(cursor.description):
tmp_row[col[0]] = row[idx]
hatebu_list.append(tmp_row)
connect.close()
# Slackのチャンネル一覧を取得
slack = Slack("SlackのToken")
channel_list = slack.get_channnel_list()
return template('hatebu’, hatebu_list=hatebu_list, channel_list=channel_list)
[/python]
sites/views/hatebu.html を以下のように編集
(formはここで紹介したように記述している。)
作成ボタンが押された場合は、 /hatebu_create に
更新ボタン、削除ボタンが押された場合は、 /hatebu_updel に移動して処理する。
実際の作成・更新・削除の処理は次回実装する。
[html title="hatebu.html"]
{% extends 'base.html’ %}
{# base.html の title の中に入れるコンテンツ #}
{% block title %}
Slackツール
{% endblock %}
{# ヘッダー情報を追加する場合はここに記述する。 #}
{% block header %}
{% endblock%}
{# base.html の contents の中に入れるコンテンツ #}
{% block contents %}
<h1>Slackツール</h1>
<div>
<form action="/hatebu_create" method="get" accept-charset="utf-8" id="create"></form>
<table class="table">
<tbody>
<tr>
<td>チャンネル</td>
<td>
<select name="channel" form="create">
{% for cl in channel_list %}
<option value="{{cl.channel_name}}">{{cl.channel_name}}</option>
{% endfor %}
</select>
</td>
</tr>
<tr>
<td>キーワード</td>
<td><input type="text" name="word" form="create" placeholder="キーワード" /></td>
</tr>
<tr>
<td>取得するブックマーク数</td>
<td><input type="number" name="bookmark_count" form="create" placeholder="ブックマーク数" /></td>
</tr>
<tr>
<td></td>
<td><input type="submit" name="create" value="作成" form="create" class="btn btn-success" /></td>
</tr>
</tbody>
</table>
</div>
<div>
<table class="table table-striped">
<thead>
<tr>
<td>ID</td>
<td>チャンネル</td>
<td>キーワード</td>
<td>取得するブックマーク数</td>
<td>更新</td>
<td>削除</td>
</tr>
</thead>
<tbody>
{% for hl in hatebu_list %}
<tr>
<td>
{{hl.id}}
<input type="hidden" name="id" form="form{{hl.id}}" value="{{hl.id}}" />
</td>
<td>
<select name="channel" form="form{{hl.id}}">
{% for cl in channel_list %}
{# 登録されているBOTのチャンネルと一致している場合は選択されているようにする。 #}
{% if cl.channel_name == hl.channel %}
<option value="{{cl.channel_name}}" selected="selected">{{cl.channel_name}}</option>
{% else %}
<option value="{{cl.channel_name}}">{{cl.channel_name}}</option>
{% endif %}
{% endfor %}
</select>
</td>
<td>
<input type="text" name="word" form="form{{hl.id}}" value="{{hl.word}}" />
</td>
<td>
<input type="number" name="bookmark_count" form="form{{hl.id}}" value="{{hl.bookmark_count}}" />
</td>
<td>
<input type="submit" name="updel" form="form{{hl.id}}" value="更新" class="btn btn-info" />
</td>
<td>
<input type="submit" name="updel" form="form{{hl.id}}" value="削除" class="btn btn-danger" />
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% for hl in hatebu_list %}
<form action="/hatebu_updel" method="get" id="form{{hl.id}}" accept-charset="utf-8"></form>
{% endfor %}
{% endblock %}
[/html]
sites.pyを実行し、https://localhost:8080/hatebu にアクセスしてデータが表示されたら、とりあえずUI風完成。
次回、作成・更新・削除の実装を紹介する。
続き:
ディスカッション
コメント一覧
まだ、コメントがありません