line bot 作成の覚え書き

初版作成  2022.3.24
最終更新  2022.05.20


◆◆ line bot の概念 ◆◆


2 つのことができる

(1) push : 投稿する

具体的には https://api.line.me/v2/bot/message/push に
対して json 形式のデータを POST する

(2) reply : 投稿されたメッセージを読み取り、応答メッセージを投稿する

具体的には、投稿されたメッセージを受信する url を用意し、
cgi プログラムを配置する。
その url に対して json 形式のデータが POST されてくる。

応答を json 形式で用意し、
https://api.line.me/v2/bot/message/reply に POST する。

必要な json の内容は若干異なるが、
https://api.line.me/v2/bot/message/push に POST しても
投稿に対応して、応答を投稿するという機能は
同じであると思われる。


◆◆ 準備 ◆◆


チュートリアル:#_#link#https://developers.line.biz/ja/docs/messaging-api/line-bot-sdk/#https://developers.line.biz/ja/docs/messaging-api/line-bot-sdk/#

- line developer へ登録する(無料)
  developers.line.biz/ja/

- プロバイダを新規作成

- チャンネルを新規作成
 チャンネル名が Line の公式アカウントとなる
  チャンネルの種類は Messaging API

- QR コードを使ってスマホで Line に参加する

スマホで Line を起動し、
ホームの 上方の検索窓の右端の [ ] をタップして
QR コードを読み取ると、友達追加の画面になり
友達追加をタップする。

その友達のトークルームが見あたらない。
もういちど、QR コードを読み取らせると、その友達のトークルームが
出現する。

- メッセージを送ったらコールされる url を設定する
 Message API settings のタブを押す
 Webhook URL を入力し更新する(https でないとダメ)
 Webhook の利用を on にする

- 一番下に channel access token がある
 issue を押してトークンを取得する


◆◆ 投稿に必要な情報 ◆◆


- push に必要な情報は以下の 2 つ

channel access token
user id

push は普通のパソコンからできる。

- reply は投稿データを受信する url が必要
 json データが送られてくる。その中に投稿データと
 replyToken が入っている

応答の投稿には来たデータの中にある replyToken と
channel access token が必要


◆◆ 投稿データを受信する url ◆◆


以下の 4 つが考えられる

(1) Google

google drive に google Apps Script を作成し、
「デプロイする」のボタンを押すと、
そのスクリプトに url が割り当てられ、
POST されたデータを受け取ることができる。

プログラムを変更した場合、デプロイし直す
必要があり、url が変わるので、開発効率が
悪い。

しかし、無料で使える環境の中では
最も優れた環境であると思われる。

(2) lolipop などのレンタルサーバ

python でプログラムを書くなら、これが一番やりやすい。
月 400 円~ 700 円程度かかるが、python を使って
開発したいなら、開発効率は高い。
ただし、lolipop ではエラーログを見ることができないので、
開発効率が悪い。

(3) heroku

heroku という無料で web アプリを配置できるサービスがある。
プログラムを手元の PC で作成し、heroku という独自コマンドと
git コマンドを利用して、プログラムの作成とアップロードを行う。

この方法は flask を用いたサンプルプログラムが
ネットに多数あるが、以下の欠点があり、開発効率が
絶望的に悪い。

 > cme.exe において CLI (command line interface) の操作が必要
 > git のシステムを理解し、コマンドを使いこなすのは敷居が高い
 > git でアップロードするのにある程度時間がかかる。
  レンタルサーバを用いる方法だと、ssh で接続し、
  プログラムを修正してセーブしたら、即実行可能である。
 > flask は web サーバーを立てるモジュールである。
  heroku の https (443) ポートに来たアクセスを、
  ポート番号 5000 に転送し、5000 番で待っている flask サーバ
  が処理するという方法である。
  その概念を理解するのに時間がかかる。
 > flask を利用したプログラムはデコレータを利用しており、
  非常に難易度が高い。
 > heroku は 30 分経つとスリープ状態になるので実用的では
  ないらしい。
 > レンタルサーバで flask で受ける場合 443 ではなく 8080 などの
  番号で受けることになる。その場合、SSL のエンコードとデコードを
  自力で行う必要があり、証明書の取得など難易度が高い。

(4) 自前のサーバ

自力でサーバを用意し、グローバル IP を取得し、
外部からアクセスできるようにする。
非常に敷居が高いが、スクリプトでエラーが発生したとき、
access_log, error_log を即座に確認できるので
開発効率は最も高いと思われる。

◆◆ 開発方法 ◆◆


以下のようにすると開発効率が高いと思われる (Windows マシン使用)

・PC 版 Line をインストールし、Line への投稿、確認は PC で行う。
 投稿は alt+Enter ではなく Enter でできるようにしておいた方が操作性がよい。
 ウィンドウ左下の非常に薄い文字の「設定」をクリック

・Web ブラウザは Line Developer のサイト(投稿を受け取る url の
 設定変更に必要)、投稿を受け取る url を常に開いておく。

・プログラムは Google Apps Script で開発するならブラウザで、
 レンタルサーバで python を使うなら、teraterm などで ssh 接続
 してプログラミングする。


◆◆ python モジュールのインストール ◆◆


$ pip3 install line-bot-sdk
$ pip3 install requests

flask を使う場合、ファイル名を flask.py とすると、
import するときに自分を import しようとして
エラーが出るので注意。


◆◆ python (push text: line_bot_api 使用) ◆◆


プログラムは最もシンプルになる

import sys
from linebot import LineBotApi
from linebot.models import TextSendMessage

token = 'トークンの値'
user_id = "id の値'

lines = "push line bot"
messages = TextSendMessage(text=lines)
print(messages)

line_bot_api = LineBotApi(token)
line_bot_api.push_message(user_id, messages=messages)

◆◆ python (push text: json 形式のデータの合成を自力で行う) ◆◆


import requests
import json

token = "トークンの値"
user_id = "id の値"

api_url = 'https://api.line.me/v2/bot/message/push'

token_dic = {"Content-Type": "application/json",  "Authorization": "Bearer " + token}
send_dic = {"to": user_id, "messages":[{"type":"text", "text":"spush message"}]}
send_dic_json = json.dumps(send_dic)

requests.post(api_url, headers=token_dic, data=send_dic_json)

◆◆ python (push image: line_bot_api 使用) ◆◆


画像はあらかじめ、どこかの url に配置する必要がある

import linebot
from linebot import LineBotApi
from linebot.models import TextSendMessage
from linebot.models import ImageSendMessage

token = 'トークン'
user_id = 'user id'

image_url = "https://xxx.yyy.zzz/dir/fname.jpg"
image_message = ImageSendMessage(
    original_content_url = image_url,
    preview_image_url = image_url)

print(image_message)

line_bot_api = LineBotApi(token)
line_bot_api.push_message(user_id, messages=image_message)

◆◆ python (push image: json 形式のデータの合成を自力で行う) ◆◆


import requests
import json

token = 'トークンの値'
user_id = 'user id の値'
api_url = 'https://api.line.me/v2/bot/message/push'

image_url = 'https://xxx.yyy.zzz/dir1/fname.jpg'

token_dic = {"Content-Type": "application/json",  \
             "Authorization": "Bearer " + token}
send_dic = {"to": user_id, \
            "messages": [ {"type": "image", \
                           "originalContentUrl": image_url, \
                           "previewImageUrl":    image_url, \
                          }
                        ] \
            }
send_dic_json = json.dumps(send_dic)

requests.post(api_url, headers=token_dic, data=send_dic_json)

◆◆ python (reply text & image: line_bot_api 使用) ◆◆


import json
import sys
import datetime
import linebot
from linebot import LineBotApi
from linebot.models import TextSendMessage
from linebot.models import ImageSendMessage

token = 'トークン'
line_bot_api = LineBotApi(token)
data = json.load(sys.stdin)

text = data["events"][0]["message"]["text"]
replyToken = data["events"][0]["replyToken"]

# ファイルに書き出して確認

f = open("json.txt","w")
print(json.dumps(data), file = f)
f.close()

# 応答の例

if text == "t":
    messages = "reply by text"
    line_bot_api.reply_message(replyToken, TextSendMessage(text=messages))
elif text == "c":
    image_url = "https://aaa.bbb.jp/dir/image.jpg"
    image_message = ImageSendMessage(
        original_content_url = image_url,
        preview_image_url = image_url)
    line_bot_api.reply_message(replyToken, image_message)
else:
    messages = "no action"
    line_bot_api.reply_message(replyToken, TextSendMessage(text=messages))

◆◆ python (reply text: json データを自力で合成) ◆◆


import requests
import json
import sys

token = "トークンの内容"
url = 'https://api.line.me/v2/bot/message/reply'

data = json.load(sys.stdin)
text = data["events"][0]["message"]["text"]
replyToken = data["events"][0]["replyToken"]

# ファイルに書き出して確認

f = open("json.txt","w")
print(json.dumps(data), file = f)
f.close()

# 応答の例

if text == "a":
    message = "you input a"
elif text == "b":
    message = "you input b"
else:
    message = "you input other"

token_dic = {"Content-Type": "application/json",  \
             "Authorization": "Bearer " + token}
send_dic = {"replyToken": replyToken, \
            "messages":[{"type":"text", "text": message}]}

send_dic_json = json.dumps(send_dic)
requests.post(url, headers=token_dic, data=send_dic_json)


◆◆ 受信用 url として lolipop を使う場合の設定 ◆◆


(1) line-bot-sdk のインストール

参考サイト
https://dattesar.com/lolipop-pip-flask/

- pip3 をインストールする
$ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
$ python3 get-pip.py --user

- path を通す
~/.bash_profile に以下を記述

PATH=$PATH:/home/users/0/xxxxxxx/.local/bin
export PATH

$ . ~/.bash_profile

- ライブラリのインストール

$ pip3 install line-bot-sdk

既にインストールされているライブラリの確認法
$ pip3 freeze

- cgi を配置する  chmod 755 を忘れずに

cgi は www-data ではなく、自分の権限で動作する。
ディレクトリを 777 にするとエラーになるので要注意


◆◆ json 形式の取り扱い方 ◆◆


○ JavaScript での使い方

let data = {"key1": "data1", "key2": ["a","b"]};

a = data.key1;
b = data[1].key2;    配列へのアクセス


○ python での使い方

・web 上にあるファイルからの読み込み

url = 'https://www.jma.go.jp/bosai/forecast/data/overview_forecast/130000.json'
req = urllib.request.urlopen(url)
page = req.read().decode()   # このサイトは decode() はなくても同じ結果
print(page)

dic = json.loads(page)

print(dic['reportDatetime'])    # 1 つのフィールドを表示

for key in dic.keys():  # .keys() はなくてもよい
    print("key = " + key + "  value = " + dic[key])

・ファイルからの読み込み

f = open(fname, "r")
dic = json.load(f)
以下同じ