初老のボケ防止日記

おっさんのひとりごとだから気にしないようにな。

LINE BOT APIを使ってPythonでLINE BOTを作ってみた

9割方、使えない情報だが疲れたので残す。


今朝、TLを眺めていて初めて知った。

linecorp.com

全世界のサードパーティデベロッパーを想定した先着1万名限定で、BOTアカウントを自由に開発できる「BOT API Trial Account」の無償提供を開始いたしました。希望者は、本日開設したLINE@やLINE Loginなどの申込・管理ができるLINEのビジネス向けポータルサイト「LINE BUSINESS CENTER」https://business.line.me から、利用登録を行い、BOTアカウントの作成・開発を行うことができます。

先着と聞いて、とりあえず作ってみた。

LINE BOT作ってみた

午後から用事があるので、以下の手順にしたがってささっと作ろうかなと思ったのだが…

https://developers.line.me/type-of-accounts/bot-api-trial

一筋縄ではいかなかった。

webhookなので外部アクセス可能なサーバ必要

これはまあしょうが無いよなーということで、最近触り始めたAWSのEC2でUbuntu 14.04のインスタンスを構築。

docs.aws.amazon.com

$ sudo apt-get install python3-pip
$ sudo pip3 install --upgrade pip
$ sudo pip3 install flask

とりあえずPythonだけでWebサーバ立ち上げたいので今回はFlaskを使ってみた。

Welcome | Flask (A Python Microframework)

コールバックURLはhttpsのみ

ところが、コールバックURLに指定できるのはHTTPSのみ。しかもHTTPSのデフォルトポート(443)なのにURLにポートを明記しない登録させてもらえない。ということで、FlaskでHTTPSで立ち上げる方法を探し…

How to serve HTTPS *directly* from Flask (no nginx, no apache, no gunicorn) | Flask (A Python Microframework)

サーバ証明書を作り…

☆コレ要らない手順☆

$ openssl genrsa 2048 > server.key
$ openssl req -new -key server.key > server.csr
$ openssl x509 -days 3650 -req -signkey server.key < server.csr > server.crt

オレオレ証明書は弾かれる

ブラウザからはアクセスできるのに、LINEからコールバックURLがコールされない。公式のドキュメントをよく見ると…

Note: The SSL certificate must be issued by an authorized CA. If a self-issued SSL certificate is applied to your server, requests sent from the LINE platform will fail.

オレオレはアカンぞと。

サーバ証明書発行するためにドメイン名が必要

しかたがないのでサーバ証明書を作りましょう。今時はコイツで無料で作れまししね!

letsencrypt.org

でも証明書作成にドメイン名がいるんだな。しかもEC2で作成したインスタンスのパブリックDNSを使用するとエラーで生成できない。ということで、

自前ドメインを取得してEC2のインスタンスと紐付けるのだ。ところがEC2のインスタンスは再起動するとIPアドレスが変動するのでElastic IPで固定化するのだ。

docs.aws.amazon.com

Let's Encryptで作った証明書だとダメっぽい

ふふふ。これでサーバ証明書を生成すれば動くだろう。とその時は思ったいた…

☆コレ要らない手順☆

$ sudo apt-get install git
$ git clone https://github.com/letsencrypt/letsencrypt
$ cd letsencrypt/
$ .local/share/letsencrypt/bin/letsencrypt --help
Bootstrapping dependencies for Debian-based OSes...
(snip)
Installation succeeded.
Requesting root privileges to run letsencrypt...
   sudo /home/ubuntu/.local/share/letsencrypt/bin/letsencrypt --help

  letsencrypt-auto [SUBCOMMAND] [options] [-d domain] [-d domain] ...
(snip)

$ sudo .local/share/letsencrypt/bin/letsencrypt certonly

ところが、LINEからコールバックURLがコールされない。Twitterで検索すると…

阿鼻叫喚の嵐。

テスト用に無料でSSL証明書を生成

ということで、今回はコチラのテスト用を利用させて頂いた。

jp.globalsign.com

ありがとうございました。グローバルサイン様

なお、証明書作成時にはドメイン所有権の確認のメールがドメイン管理者に飛ぶので独自ドメインを保有していないと駄目。さらに、「スキップ申込サービス」っていうのでやると

CSRと秘密鍵を用意しなくてもいい。

スキップ申込サービス|GMOグローバルサイン【公式】

サーバに関する専門知識がない方にも簡単にサーバ証明書を取得することができます。また、サーバの準備が完了してない段階でのお申し込みも可能です。
グローバルサインで生成した秘密鍵は、証明書発行後、PKCS#12形式で安全にお客様にお渡しいたします

グローバルサインさん、

親切。

でも、PKCS#12形式だとFlaskで使えない(調べてない)のでPEMにしないと…

OpenSSL PKCS#12操作 — SSLサーバ証明書のクロストラスト -

ヒャッハー! これでちゃんとしたSSL証明書でFlaskがHTTPS起動したぜ!

ということで、完成

ふう。ということでSSL証明書さえあればチョロい。ってそれでもAPIリファレンスみながら試行錯誤だが。

from flask import Flask
from flask import request

import requests
import json
import re

LINEBOT_API_EVENT ='https://trialbot-api.line.me/v1/events'
LINE_HEADERS = {
    'Content-type': 'application/json; charset=UTF-8',
    'X-Line-ChannelID':'XXXXXXX', # Channel ID
    'X-Line-ChannelSecret':'XXXXXXXXXXXXXXXXXXXXXXXXXXX', # Channel secre
    'X-Line-Trusted-User-With-ACL':'XXXXXXXXXXXXXXXXXXXXXXXXXX' # MID (of Channel)
}

def post_event( to, content):
    msg = {
        'to': [to],
        'toChannel': 1383378250, # Fixed  value
        'eventType': "138311608800106203", # Fixed value
        'content': content
    }
    r = requests.post(LINEBOT_API_EVENT, headers=LINE_HEADERS, data=json.dumps(msg))

def post_text( to, text ):
    content = {
        'contentType':1,
        'toType':1,
        'text':text,
    }
    post_event(to, content)


commands = (
    (re.compile('ラッシャー', 0), lambda x: 'テメエコノヤロウ'),
    (re.compile('ダンカン', 0), lambda x:'バカヤロコノヤロウ'),
)

app = Flask(__name__)

@app.route("/callback", methods=['POST'])
def hello():
    msgs = request.json['result']
    for msg in msgs:
        text = msg['content']['text']
        for matcher, action in commands:
            if matcher.search(text):
                response = action(text)
                break
        else:
            response = 'コマネチ'

        post_text(msg['content']['from'],response)

    return ''

if __name__ == "__main__":
    context = ('cert/server.pem', 'cert/privkey.pem')
    app.run(host='0.0.0.0', port=443, ssl_context=context, threaded=True, debug=True)

ウェルノウンポートなのでsudoで実行だ。

試してみましょう

f:id:osa030:20160408205950j:plain

デベロッパーコンソールのBOT情報のQRコードから友達に追加。

f:id:osa030:20160408205956j:plain

BOTの作成者とかアクセスする情報とかが表示されるようだ。

f:id:osa030:20160408210002j:plain

で、こんな感じになりました。

Flask Web Development: Developing Web Applications with Python

Flask Web Development: Developing Web Applications with Python

Pythonプロフェッショナルプログラミング 第2版

Pythonプロフェッショナルプログラミング 第2版