Amazon Echoに西鉄バスの到着時刻を教えて貰う(非公式)

# はじめに
GoogleHomeの方が個人的には好き。
EchoPlus買ったけど、重低音きつくて音楽聴くには向いてない。。。
(しかもSpotify未対応。。。え？いいとこないじゃん。。。)

我が家のEchoは[豆しばのスキル](https://smarthacks.jp/db/739/)しか使っていないので、
何か仕事をさせてあげたいと思い今回よく利用する西鉄バスの到着時刻を教えて貰うスキルを作成しました。

以下~~をパクらせて頂きました。~~参考にさせて頂きました。
[@osa9さん](https://qiita.com/osa9)の[Amazon Echoにバスの到着時刻を教えて貰う](https://qiita.com/osa9/items/e2cc6318b7ed736ac6ff)

# AWS Lambdaで処理を作成
## 関数の作成
Lambda>関数の作成
Pythonを使用しているので、値を以下のようにセットし、「関数の作成」を押下(名前は何でもOK)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/153587/75205624-0b5c-5eca-8ea6-71a748ec48a8.png)

トリガーの追加から、「Alexa Skills Kit」を選択、
スキルID検証は「無効」でOK

## 関数コード
「BUS_SCHEDULE_URL」については、必要な情報に合わせてパラメータ等変更して下さい。
[にしてつ時刻表　テキスト版](https://jik.nishitetsu.jp/am/)

```python:alexa_bus.py
import logging
import traceback,sys
import urllib.request
from bs4 import BeautifulSoup

# 西鉄バス時刻表(テキスト版)運行状況のURL(サンプルは百年橋 → 博多駅筑紫口)
BUS_SCHEDULE_URL = 'https://jik.nishitetsu.jp/am/route?ftKbn=t&f_list=0001%2C550013&t_list=0000%2CD00209&btnSearchFT=%8C%9F%8D%F5&jkn_busnavi=1'


# 西鉄バスのリアルタイム運行状況を取得する
def get_bus_schedule(url):
    logging.info("Retrieving URL: {}".format(url))
    content = urllib.request.urlopen(url).read().decode('shift_jisx0213')
    soup = BeautifulSoup(content, "html.parser")

    # エラーメッセージがある時(バスが終了している時も含む)
    errors = soup.select('.errorTxt')
    if len(list(errors)) > 0:
        message = errors[0].contents[0]
        logging.warn("Error: ".format(message))
        raise Exception(message)

    # ダイヤをパースする
    result = []
    for bus_info in soup.find_all('form'):
        res = list(map(lambda col: col.string, bus_info.find_all('p')))

        # 取りたくないformが最後にあるので
        if len(res) == 0:
            break
        
        # スロープでない場合、以下のダミーを要素に追加
        if len(res) == 5:
            res.insert(2,'ダミー')
        
        
        info = {
            'scheduled_arrival': res[0].split()[1],  # 乗車　19:08　百年橋
            'bus_stop': res[1],  # [67] 普通　 博多駅
            'bus_route': res[3],  # 約5分遅れ 2停前通過
            'destination': res[4],  # 乗り換え0回
            'type': res[5].split()[2]  # 降車　19:19　博多駅筑紫口
        }

        result += [info]

    return result


def bus(event, context):
    logging.info(event)

    # スケジュールを取得してメッセージを組み立てる
    try:
        schedules = get_bus_schedule(BUS_SCHEDULE_URL)
        message = '{}行きのバスは、{}'.format(schedules[0]['type'], schedules[0]['scheduled_arrival'] + schedules[0]['bus_route']) + '。'
        if len(schedules) > 1:
            message += 'その次は、{}'.format(schedules[1]['scheduled_arrival'] + schedules[1]['bus_route']) + '。'
        if len(schedules) > 2:
            message += ' その次は、{}'.format(schedules[2]['scheduled_arrival'] + schedules[2]['bus_route']) + '。'
        if len(schedules) > 3:
            message += ' その次は、{}'.format(schedules[3]['scheduled_arrival'] + schedules[3]['bus_route']) + '。'
    except:
        ex,ms,tb=sys.exc_info()
        message = 'エラー {}'.format(ms)

    logging.info(message)

    response = {
        'version': '1.0',
        'response': {
            'outputSpeech': {
                'type': 'PlainText',
                'text': message,
            }
        }
    }

    return response

# テスト用
if __name__ == '__main__':
    print(bus(None, None))
```

## 注意点
上記「alexa_bus.py」では、beautifulsoupを利用し、スクレイピングを行っている為、パッケージを含めた状態で、zipファイルをアップロードする必要があります。
(各パッケージについては、Windows,Macそれぞれ、pythonのディレクトリ内にあるはずです。なければ、pipでパッケージの取得が必要です。)
※zipファイルを作成する際、ディレクトリを圧縮するのではなく、以下赤枠のように対象ファイルを選択し、圧縮する必要があります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/153587/b8ae91da-1fce-6c50-a992-024d5dbd6fbb.png)

zipファイルをアップロード>ハンドラを変更>保存
![image.png](https://qiita-image-store.s3.amazonaws.com/0/153587/61eb6138-6db4-a626-c051-09acbc3f643a.png)


# 3.AlexaSkil作成
[Amazon開発者ポータル](https://developer.amazon.com/ja/)を開きログイン
(※[Alexa 開発者アカウント作成時のハマりどころ](https://developer.amazon.com/ja/blogs/alexa/post/9f852a38-3a44-48bd-b78f-22050269d7c7/hamaridokoro))

## Alexa Skills Kit
個人的には以前のコンソールの方が日本語でわかりやすいですが、今回は新しいコンソールを使ってスキルを作成します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/153587/fdff8702-1d0e-890d-9c3e-3094c3df1be1.png)

スキル名、言語を設定
![image.png](https://qiita-image-store.s3.amazonaws.com/0/153587/851c4d66-6d3e-4de1-1314-bbc4a0422a56.png)

とりあえずCustomを選択
![image.png](https://qiita-image-store.s3.amazonaws.com/0/153587/cd533694-ed02-0978-ec7c-b0668c8196f7.png)

以下赤枠内のチェックリストをそれぞれ設定
![image.png](https://qiita-image-store.s3.amazonaws.com/0/153587/8534602b-eb43-a03a-b2ee-899407910af5.png)

1.Invocation Name>「時刻表」を設定
2.Intents,Samples,and Slotsについては、以下を設定
![image.png](https://qiita-image-store.s3.amazonaws.com/0/153587/716644ef-db45-9d15-0b4d-b91d056b217c.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/153587/29946048-d42c-e5ab-33d2-3dbcababe83f.png)
3.Build Model押下にて、Buildが開始されます。
4.EndpointでDefault Regionの欄にLambda関数画面の右上にあるARNを貼り付け
![image.png](https://qiita-image-store.s3.amazonaws.com/0/153587/670e7f23-e7f0-2285-7d2d-9715ba688e1b.png)


# 4.テスト
「時刻表を開いて、次のバスは」と入力すると以下の結果が得られます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/153587/16d827e3-b420-4100-d8ce-92b9ab8afed9.png)

Echo持っている方は、「有効なスキル」>「DEVスキル」で「西鉄バス時刻表」のスキルを有効にすれば、使えるはずです。
Echo持ってなくても[Reverb](https://reverb.ai/)で確認ができます。

# 5.最後に
特に詳しいわけでもなく、先駆者の方々を真似て自分用のメモとして書きました。
バス停の指定、日時の指定も、「Alexa スロット」等で検索すれば、作れると思います。。。