70
85

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

1時間でWikipedia検索できるLINE BOTをサクッと作ってみよう!

Last updated at Posted at 2020-01-11
こんな感じのWikipedia検索できるLINE BOTを作成してみました。

思った以上に簡単に作れたので、作り方を紹介します。
時間測ってないですが、初心者でも1時間あれば全然作れる気がします(知らんけど)
振り返りながら書いているので、手順が抜けていたらごめんなさい...
今回は、python(Flask)で開発し、herokuにデプロイしていきます。

#LINE Developersの登録
まずはじめに、LINE Developersに登録しましょう。
https://developers.line.biz/ja/ へアクセス

スクリーンショット 2020-01-07 22.36.57.png 右上のログインをクリック 多くの人はLINEのアカウントをお持ちかと思いますので、そのまま登録してしまいましょう。

登録後、サービス提供者を表す「プロバイダー」を作成。
続けて、登録したプロバイダー内で新規チャネルを作成。
チャネルの種類はMessage APIを選択してください。

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3439313237392f64636532643562332d656532382d366235392d333732632d3837356630353034383333312e706e67-2.png また後ほど触りますが、一旦これでLINE Developersの設定はおっけーです!

#herokuの登録
続いてherokuにも登録します。
今更初めて使ったけど素晴らしい...
PaaSと呼ばれるサービスで、超簡単にデプロイできちゃいます。

  • サーバー
  • OS
  • DB
  • プログラミング言語の実行環境

といったサービス公開のために必要なものを用意してくれて、しかも無料で使えるという。
無料で使うと、挙動が遅くなってしまったりと、制約つきではありますが、簡単なLINE BOTを遊びで作るには十分かと思います。
それでは、登録していきましょう。
https://jp.heroku.com/ へアクセス

スクリーンショット 2020-01-08 0.54.18.png

右上の新規登録から、手順に沿って登録しましょう。
日本語の説明に沿って入力するだけですので、詳しい説明は割愛します。

登録完了すると、こんな画面が表示されます。
スクリーンショット 2020-01-08 0.57.44.png
続いてアプリケーションの作成をします。
コマンドでの作成も可能なのですが、今回はブラウザ上で作成します。
右上のNewをクリック、続けてCreate new appをクリックしましょう。
スクリーンショット 2020-01-08 0.58.02.png

すると次のような画面に遷移するので、名前とリージョンを選択します。どっちでも良いかと思いますが、今回、リージョンはアメリカにします。

スクリーンショット 2020-01-08 0.58.43.png スクリーンショット 2020-01-08 9.02.20.png

続いてherokuをインストールしていきます。
下記URLより、対応するOSのインストーラーから、もしくはコマンド入力でインストールします。
https://devcenter.heroku.com/articles/heroku-cli#download-and-install

インストールするとherokuのコマンドラインが使えるようになります。
まずはログインしてみましょう。

$ heroku login

すると、メールアドレスとパスワードを求められるので、heroku登録時のアドレスとパスワードを入力しましょう。

Enter your Heroku credentials:
Email: 登録したアドレスを入力
Password: 登録したパスワードを入力

これでログイン完了できたかと思います。

続いて、環境変数を設定していきましょう。
環境変数とは?: https://wa3.i-3-i.info/word11027.html

$ heroku config:set YOUR_CHANNEL_ACCESS_TOKEN="チャネルアクセストークンの文字列" -a アプリケーション名
$ heroku config:set YOUR_CHANNEL_SECRET="チャネルシークレットの文字列" -a アプリケーション名

アプリケーション名は先ほど決めたherokuのApp name、
「アクセストークンの文字列」と「チャネルシークレットの文字列」はLine developersで以下のように確認可能です。

まずは、チャネルアクセストークンの確認。
スクリーンショット_2020-01-09_23_49_32.png
スクリーンショット_2020-01-09_23_49_47.png
スクリーンショット_2020-01-09_23_51_31-2.png
続けて、チャネルシークレットの確認
スクリーンショット_2020-01-09_23_51_13.png
スクリーンショット_2020-01-09_23_51_13-2-2.png
スクリーンショット_2020-01-09_23_51_17-2.png

これで、「YOUR_CHANNEL_ACCESS_TOKEN」と「YOUR_CHANNEL_SECRET」という環境変数がデプロイ先で使えるようになりました。

ここまでできたらコードを書いていきましょう。pythonで書いていきます。

まず、以下のようにファイル、およびフォルダを作成してください。

lineBot
├── Procfile
├── main.py
├── runtime.txt
└── requirements.txt

作成した後、以下のように作成したファイルに入力していきます。

Pythonのバージョンを記載

runtime.txt
python-3.6.6

インストールするライブラリを記載する設定ファイル

requirements.txt
Flask==0.12.2
line-bot-sdk==1.5.0

今回は小規模なアプリケーションでも対応しやすいマイクロフレームワーク、flaskを使って開発します。
LINE Messaging API SDKは、LINE BOT開発のためのライブラリです。
参考: https://developers.line.biz/ja/docs/messaging-api/line-bot-sdk/

プログラムの実行方法を定義する設定ファイル

# Procfile
web: python main.py

あとは、main.pyに先ほどのLINE Messaging API SDKのリンク先にあるpythonの公式SDKからコードを引用します。
pythonの公式SDK: https://github.com/line/line-bot-sdk-python

ここのSynopsisに記載されるコードがオウム返しのLINE BOTになっています。
少し変更する必要がありますが、基本的には引用でいけるので、一旦、main.pyにコピペします。

main.py
from flask import Flask, request, abort

from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,
)

app = Flask(__name__)

line_bot_api = LineBotApi('YOUR_CHANNEL_ACCESS_TOKEN')
handler = WebhookHandler('YOUR_CHANNEL_SECRET')


@app.route("/callback", methods=['POST'])
def callback():
    # get X-Line-Signature header value
    signature = request.headers['X-Line-Signature']

    # get request body as text
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    # handle webhook body
    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        print("Invalid signature. Please check your channel access token/channel secret.")
        abort(400)

    return 'OK'


@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=event.message.text))


if __name__ == "__main__":
    app.run()

コードを読んでみると、先ほど定義したherokuの2つの環境変数ではなく、直接代入される形になってしまっているので、これを書き換えます。

main.py
from flask import Flask, request, abort
from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,
)
import os

app = Flask(__name__)

YOUR_CHANNEL_ACCESS_TOKEN = os.environ["YOUR_CHANNEL_ACCESS_TOKEN"]
YOUR_CHANNEL_SECRET = os.environ["YOUR_CHANNEL_SECRET"]

line_bot_api = LineBotApi(YOUR_CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(YOUR_CHANNEL_SECRET)


@app.route("/callback", methods=['POST'])
def callback():
    # get X-Line-Signature header value
    signature = request.headers['X-Line-Signature']

    # get request body as text
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    # handle webhook body
    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        print("Invalid signature. Please check your channel access token/channel secret.")
        abort(400)

    return 'OK'


@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=event.message.text))


if __name__ == "__main__":
    port = int(os.getenv("PORT", 5000))
    app.run(host="0.0.0.0", port=port)

変更箇所は以下の通りです。

.py
# 追加
import os

app = Flask(__name__)

# 追加
YOUR_CHANNEL_ACCESS_TOKEN = os.environ["YOUR_CHANNEL_ACCESS_TOKEN"]
YOUR_CHANNEL_SECRET = os.environ["YOUR_CHANNEL_SECRET"]

line_bot_api = LineBotApi(YOUR_CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(YOUR_CHANNEL_SECRET)

//省略//

# 変更
if __name__ == "__main__":
    port = int(os.getenv("PORT", 5000))
    app.run(host="0.0.0.0", port=port)

これで、定義したOSの環境変数を使用することができます。

ざっくりですが、コード解説

.py
@app.route("/callback", methods=['POST'])
def callback():
    # get X-Line-Signature header value
    signature = request.headers['X-Line-Signature']

    # get request body as text
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    # handle webhook body
    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        print("Invalid signature. Please check your channel access token/channel secret.")
        abort(400)

    return 'OK'

/callbackへPOSTすると、Webhook(後ほど出てきます)からのリクエストをチェックし、正しく帰ってきたとき、handlerに定義されている関数が呼び出されます。

.py
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=event.message.text))

LINEメッセージが正しく送信できると、関数handle_messageが呼び出され、reply_messageの第2引数の値がLINEの返信として返されます。

ここで一度、herokuへデプロイしてみましょう。

$ cd 作成したディレクトリ/
$ git init
$ heroku git:remote -a アプリケーション名
$ git add .
$ git commit -am "make it better"
$ git push heroku master

正しくpushできていれば、

$ git branch -a

remotes/heroku/master

と表示されるはずです。

#Webhookの設定
Webhookとは、あるアプリケーションから別のアプリケーションにリアルタイムに情報を送信するための仕組みです。
LINE BOTのイベント通知を、リアルタイムに行うために使います。
設定を行うために、再度、Line Developersにアクセスします。
スクリーンショット_2020-01-11_1_02_05.png

Message APIの設定 > Webhook設定に

https://<アプリケーション名>.herokuapp.com/callback

を入力、Webhookの利用をオンにしましょう。
これでオウム返しするようになります。ぜひ実際にラインを送ってみてください。
Line Developers の Message APIの設定 にQRコードがあるので、そこから作成したLINE BOTを友達登録して、会話してみましょう。

ただし、このままの設定だと、「あいさつメッセージ」やラインを送信した際に返ってくる「応答メッセージ」など余計なメッセージが表示されてしまいます。
Messaging API設定からあいさつメッセージの内容の変更、または無効化、応答メッセージの無効化など設定できるので修正してください。
スクリーンショット_2020_01_13_1_26.png

#Wikipedia検索できるようにする
オウム返しするだけだと面白くないので、
WikipediaのAPIを使って検索できるようにしてみましょう。
参考: https://pypi.org/project/wikipedia/

まずはWikipediaのライブラリを登録

requirements.txt
Flask==0.12.2
line-bot-sdk==1.5.0
wikipedia==1.4.0 # 追加

続いて、先ほどのmain.pyを以下のように書き換えます。

main.py
from flask import Flask, request, abort
from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,
)
import os
import wikipedia # 追加

app = Flask(__name__)

YOUR_CHANNEL_ACCESS_TOKEN = os.environ["YOUR_CHANNEL_ACCESS_TOKEN"]
YOUR_CHANNEL_SECRET = os.environ["YOUR_CHANNEL_SECRET"]

line_bot_api = LineBotApi(YOUR_CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(YOUR_CHANNEL_SECRET)

wikipedia.set_lang("ja") # 追加

@app.route("/callback", methods=['POST'])
def callback():
    signature = request.headers['X-Line-Signature']
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        abort(400)
    return 'OK'

@handler.add(MessageEvent, message=TextMessage)
# 先ほどの関数内にWikipediaのライブラリを使った処理を記述していく
def handle_message(event):
    send_message = event.message.text
    # 正常に検索結果が返った場合
    try:
        wikipedia_page = wikipedia.page(send_message)
        # wikipedia.page()の処理で、ページ情報が取得できれば、以下のようにタイトル、リンク、サマリーが取得できる。
        wikipedia_title = wikipedia_page.title
        wikipedia_url = wikipedia_page.url
        wikipedia_summary = wikipedia.summary(send_message)
        reply_message = '' + wikipedia_title + '\n' + wikipedia_summary + '\n\n' + '【詳しくはこちら】\n' + wikipedia_url
    # ページが見つからなかった場合
    except wikipedia.exceptions.PageError:
        reply_message = '' + send_message + '\nについての情報は見つかりませんでした。'
    # 曖昧さ回避にひっかかった場合
    except wikipedia.exceptions.DisambiguationError as e:
        disambiguation_list = e.options
        reply_message = '複数の候補が返ってきました。以下の候補から、お探しの用語に近いものを再入力してください。\n\n'
        for word in disambiguation_list:
            reply_message += '' + word + '\n'
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(reply_message)
    )

if __name__ == "__main__":
    port = int(os.getenv("PORT", 5000))
    app.run(host="0.0.0.0", port=port)

上記のコードで1番最初のtwitterに掲載したようなものが作成できました。
再びデプロイして、挙動を確かめてみてください。

一応これで完成なのですが、wikipedia内で検索してもらえれば分かる通り、日本語検索のアルゴリズムがかなり微妙なので、返ってくるワードがしっくりこなかったりします。多分しゃーない。

以上で解説は終わりです。
色々応用できると思いますので、ぜひともオリジナルのLINE BOTを作成してみてください。
結構急いで書いたので、抜け、漏れ、改善点などあればご指摘いただけますと幸いです。

#最後に
以下は弊社の宣伝になります。

現在弊社では、HRモンスターと呼ばれる
採用の新しいスタイルを提供するサービスをローンチいたしました。

ローンチ後のさらなる機能追加、改善などのPDCAサイクルを回すべく、
エンジニアを募集しております。
https://www.wantedly.com/projects/341182

Kubernetes、Vue.js(Javascript)、Django(Python)といったモダンな技術を使って、
開発しておりますので、もしご興味がある方はぜひ、ご応募お待ちしております。

70
85
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
70
85

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?