AWS Lambda＋seleniumでLineにpush通知やってみた

# この記事で言いたいこと
- web 画面のpull型確認がめんどいのでLine通知にした
- ハマったポイント


# きっかけ
- 子供が習い事をしていて、土日に練習会がある。

- 練習場所が、毎週可変
- 場所は昔ながらの掲示版でのみ知らされる。
- あれ、今週末はどこだっけ？ →わざわざ掲示版を見に行く
　↑これが面倒　→プッシュ型の通知にしたかった。
- 掲示版（sample）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445755/f4b694f4-c56b-eadb-7f3d-99df54830ebd.png)

# ひらめき
seleniumで掲示版での投稿内容を読み取って、
lamdaからプッシュ通知すればできるのでは？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445755/122e37a1-08ad-3db0-a0b8-83c0b93ad0be.png) ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445755/c580220b-00c2-f27a-7aef-900f78aadaf5.png)


# できたこと
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445755/431294f3-c7cf-5736-480f-95c098fce802.png)


# 作成にあたり
## 工夫点
 - まずは、PCローカルからselenium~line通知ができるか確認する。
 - 掲示版のどの要素を読み取るかは、chrome の開発者ツールでXPathを確認
## 仕様
 - 週に2回程度の更新なので、最新の2件のみ取得。
 - 週末だけ必要なので、水～金の18時に通知させる。
 - lambdaの課金体系がわからないが、とりあえずやってみる。

# すんなりできた点

■掲示版の最新の2件のみ取得 (python)
```python
for num in range(1,3):
   title=driver.find_element_by_xpath("/html/body/div[6]/div/div[" + str(num) + "]/h3/a")
   toukou=driver.find_element_by_xpath("/html/body/div[6]/div/div[" + str(num) + "]/p")
```

- lambda 関数の作成（経験あり）
- 定期実行させるためのCloud watch の設定
　簡単なcron 式と、lamdaを指定するだけ。（英国時間になるので注意）
- Line通知（経験あり）

# ハマった点
- python のライブラリ（=selenium）は aws Layers に搭載させる。
    lamdaにごちゃごちゃ置いても良いが、依存関係がわからなくなる。
- chrom Driver は aws Layers に搭載する必要がある。
- aws Layers がわからない・・
　→lamda から共通的に使える共通関数のようなもの。
- aws Layers への搭載の仕方や、呼び方がわからない。　
　→ここのクセが強い。

## python ライブラリ（selenium）を Layers へ搭載する方法
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445755/89ad5eba-40d2-d3e5-ade8-b7412cd6a1e6.png)

1. ↑のフォルダ構成にseleniumライブラリ一式を準備
```python
  pip install -t ./python/lib/python3.7/site-packages selenium
```
2. python フォルダ直下をzip圧縮
　（この構成を間違うと認識してくれない）
3. lambdaから importできる。（この時構成は無視）
```python
 from selenium import webdriver
```

※他のライブラリも同様

## ChromDriver を Layers に搭載する方法
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445755/8996cdc4-4a0d-efc6-bc93-053fa44e3209.png)

1. 公式配布されているchromdriver、headless-chromium の2点を準備、
（linux環境で）zip圧縮　※window環境でのzip ではダメ
2. linux環境がないので、dockerイメージを呼び出し、zip 圧縮して、Layer にアップ
3. lambdaから 以下パスを指定して呼ぶ（/opt に配置される）
```
driver = webdriver.Chrome(executable_path ="/opt/chromedriver", chrome_options=options)
```
## lambda構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445755/8c939471-2392-c0a2-e335-769f35a0b43a.png)

## layer の設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445755/72f2db05-0a07-252b-f35c-419c9f1c04d6.png)

## python コード
```python
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import urllib.parse
import urllib.request

def lambda_handler(event, context):
    LINE_NOTIFY_URL = "https://notify-api.line.me/api/notify"

    options = Options()
    options.binary_location = '/opt/headless-chromium'
    options.add_argument('--headless')
    options.add_argument('--no-sandbox')
    options.add_argument('--single-process')
    options.add_argument('--disable-dev-shm-usage')

    driver = webdriver.Chrome(executable_path ='/opt/chromedriver', chrome_options=options)
    driver.get("掲示板のURL")
    
    for num in range(1,3):
        title=driver.find_element_by_xpath("/html/body/div[6]/div/div[" + str(num) + "]/h3/a")
        toukou=driver.find_element_by_xpath("/html/body/div[6]/div/div[" + str(num) + "]/p")
        msg="\n■title:" + title.text + "\n■本文:" + toukou.text
        
        #line 通知
        method  = "POST"
        headers = {"Authorization": "Bearer %s" %　"Line認証キー"}
        payload = {"message": msg}
    
        payload = urllib.parse.urlencode(payload).encode("utf-8")
        req = urllib.request.Request(url=LINE_NOTIFY_URL, data=payload, method=method, headers=headers)
        urllib.request.urlopen(req)
```

## line メッセージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445755/8bcb4481-ffaf-75c7-9abb-4ee550fc8856.png)

# やってみて
- aws のクセにあわせるのが大変（自前でサーバ立てるよりは楽）
- alexaスキルでの実装も考えたが、投稿内容をうまく絞るのが難しそうなのでやめた。
- 掲示板に、更新通知機能があった（メール）（後でわかった）
- 課金体系はまだ調べてない。
- lambda 単体でも遅い、かつselenium も遅いので30秒くらいかかる。

## まとめ
- 身近な問題を個人で実装・解決できるのは良いこと