LINE Messaging API(v2) + API Gateway + lambda(python) で「非公式Apple整備済製品紹介」BOTを作った

## はじめに
[クローラー／Webスクレイピング Advent Calendar 2016](http://qiita.com/advent-calendar/2016/crawler)に参加していたせいか、[ボット・クローラー Advent Calendar 2016](http://qiita.com/advent-calendar/2016/bot)に招待されましたので、何か書こうということで、2016年やり残した感のあるLINE BOTを作ってみました。

## どんなBOTか
Appleの整備済製品を紹介するBOTを作りました。

![LINE_developers.png](https://qiita-image-store.s3.amazonaws.com/0/26422/71cffc90-b480-0107-3c75-f8af0e547d90.png "LINE_developers.png")

以下の特徴があります。

- Reply APIを使い入力されたテキストを含む、Apple整備済製品のページをランダムに返信する
- 「Mac」と入力したら、「Mac」を含む製品を検索する
- 検索にヒットしなかった場合は、入力されたテキストをそのまま返信（おうむ返し）する

![IMG_2687.PNG](https://qiita-image-store.s3.amazonaws.com/0/26422/ecc54520-4e51-1a0e-c430-781ef4c7aaa8.png "IMG_2687.PNG")

使ってみようかなと思った心優しい方は、下記のQRコードから「友だち追加」してみてください。
![QRコード.png](https://qiita-image-store.s3.amazonaws.com/0/26422/5d58bfc8-5bfb-8ada-262f-a2ff176d228e.png "QRコード.png")

## lambda(python)の実装
最終的にコードは以下のようになりました。

```python
from __future__ import print_function
import requests
import json
import os
import boto3
import random

print('Loading function')

LINE_API_ENDPOINT = 'https://api.line.me/v2/bot/message/reply'

LINE_API_HEADERS = {
    'Authorization': 'Bearer ' + os.environ['LINE_CHANNEL_ACCESS_TOKEN'],
    'Content-type': 'application/json'
}


def lambda_handler(event, context):

    for event in event['events']:
        reply_token = event['replyToken']
        message = event['message']

        payload = {
            'replyToken': reply_token,
            'messages': []
        }

        items = get_items_by_keyword(message['text'])
        if len(items) == 0:
            payload['messages'].append({
                'type': 'text', 'text': message['text']
            })
        else:
            item = items[0]
            payload['messages'].append({
                'type': 'text', 'text': item['title'] + item['price'] + item['link']
            })

        response = requests.post(LINE_API_ENDPOINT, headers=LINE_API_HEADERS, data=json.dumps(payload))
        print(response.status_code)


def get_items_by_keyword(keyword=None):

    key = 'items.json'
    s3 = boto3.client('s3')
    response = s3.get_object(Bucket='apple-refurbished', Key=key)
    items = json.load(response['Body'])

    result = []
    for item in items:
        if item['title'].find(keyword) != -1:
            result.append(item)

    random.shuffle(result)
    return result
```

### Messageing API -> Reply Message
[API Reference](https://devdocs.line.me/ja/#reply-message)を参考にエンドポイント、ヘッダーなどを設定します。

### Channel Access Token は環境変数から取得
Channel Access Token はLambdaの設定画面から環境変数として設定します。

![Lambda_Management_Console.png](https://qiita-image-store.s3.amazonaws.com/0/26422/c99ccd80-2bae-52ef-4cd3-f9d570cd1874.png "Lambda_Management_Console.png")

### `requests`はインストールされていないので、ZIPファイルに同梱してアップロード
`requests`をプロジェクトディレクトリの直下にインストールします。

```bash
$ cd /path/to/project
$ pip install requests -t .
```

ディレクトリーツリーは以下のようになります。

```
.
├── lambda_function.py
├── requests
│   ├── __init__.py
│   ├── ...
└── requests-2.12.4.dist-info
    ├── ...

```

ソースコードと必要な外部ライブラリをZIPファイルに圧縮して、AWS LambdaのWebコンソールからアップロードします。

参考）[デプロイパッケージの作成 (Python) - AWS Lambda](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-python-how-to-create-deployment-package.html)


### クローリングした結果は、別途、S3にJSON形式で保存
下記URLをクローリングした結果を定期にS3にJSON形式で保存するようにしておき、lambda関数からはそのJSONファイルを読み込むようにします。

- http://www.apple.com/jp/shop/browse/home/specialdeals/mac
- http://www.apple.com/jp/shop/browse/home/specialdeals/ipad
- http://www.apple.com/jp/shop/browse/home/specialdeals/ipod

## おわりに
今回のネタでは、無理だと思いますが、何かいいアイデアがあれば実装して、[LINE BOT AWARDS](https://botawards.line.me/ja/)にでもエントリーできればいいなと思います。

ではでは。