[GoogleAppsScript] 電車遅延をLINEに通知する

# はじめに
LINE Notifyを使用して電車遅延を通知するBOTを作成しました。
<img width="236" alt="IMG_5275_1.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50563/52dc3dca-7272-a0c0-250b-49e63d1f2b48.png">

GoogleAppsScript（GAS）にて1日1回通知プログラムを実行します。そのプログラムでは、[YAHOO!JAPAN路線情報](https://transit.yahoo.co.jp/diainfo/area/4/)のページ情報を取得します。そのページから電車遅延のデータを抽出して、[LINE Notify](https://notify-bot.line.me/ja/)に通知します。

```plantuml
@startuml
GoogleAppsScript -> GoogleAppsScript: 1日1回起動
activate GoogleAppsScript
  GoogleAppsScript -> "路線情報サイト": GET /diainfo
  activate "路線情報サイト"
    GoogleAppsScript <-- "路線情報サイト": HTML
  deactivate "路線情報サイト"
  GoogleAppsScript -> GoogleAppsScript: HTMLの解析
  GoogleAppsScript -> "LINE Notify": ...POST /notify
deactivate GoogleAppsScript
activate "LINE Notify"
  "LINE Notify" -> "LINE Notify": 対象のユーザーに通知
deactivate "LINE Notify"
@enduml
```

機能としては下記の通りです。

- ユーザー毎に利用する路線を指定する
- 指定した路線の遅延情報があれば通知する

# LINE Notify
- [詳しくはこちら](https://qiita.com/yun_bow/items/cc1f3c45c2d86e39c6f7)

# GoogleAppsScript
1. GoogleAppsScriptを開いて、以下のスクリプトを実装します。`LINE_NOTIFY_TOKEN`にLINE Notifyで発行したトークンを指定する。
2. `USER_REGION`に地域を指定する。
3. `USER_LIST`にユーザーごとに路線を指定する。

```JavaScript:main.gs
/**
 * 電車遅延BOT
 * 
 * YAHOO! JAPAN 路線情報: https://transit.yahoo.co.jp/
 */
const LINE_NOTIFY_TOKEN = '*****'; // LINE NOTIFY用のアクセストークン 
const region = {
    HOKKAIDO: 2, // 北海道
    TOHOKU: 3, // 東北
    KANTO: 4, // 関東
    CHUBU: 5, // 中部
    KINKI: 6, // 近畿
    KYUSYU: 7, // 九州
    CHUGOKU: 8, // 中国
    SHIKOKU: 9, // 四国
};
const USER_REGION = region.KANTO;
const USER_LIST = [{
        name: 'A男',
        routeList: ['山手線', '野岩鉄道会津鬼怒川線'],
    },
    {
        name: 'B子',
        routeList: ['銚子電鉄線', '相鉄線']
    }
];
const WEEKDAY = ["日", "月", "火", "水", "木", "金", "土"];

/**
 * メイン処理
 */
function main() {
    try {
        let userRouteList = [];
        for (let i in USER_LIST) {
            let user = USER_LIST[i];
            userRouteList = userRouteList.concat(user.routeList);
        }

        let troubleList = [];
        let srcHtml = getOperationInfo();
        let srcBlock = Parser.data(srcHtml).from('<div id="mdAreaMajorLine">').to('</div><!--/#mdAreaMajorLine-->').build();
        let srcItemList = Parser.data(srcBlock).from('<tr>').to('</tr>').iterate();
        for (let i in srcItemList) {
            let srcItem = srcItemList[i];
            let srcDataList = Parser.data(srcItem).from('<td>').to('</td>').iterate();
            let route = srcDataList[0].replace(/<a href=\"(.*?)\".*?>/, '').replace('</a>', '');
            let status = srcDataList[1] ? Parser.data(srcDataList[1]).from('<span class="colTrouble">').to('</span>').build() : null;
            let memo = srcDataList[2];
            if ('平常運転' != status) {
                for (let k in userRouteList) {
                    let userRoute = userRouteList[k];
                    if (route == userRoute) {
                        troubleList.push({
                            route: route,
                            status: status,
                            memo: memo
                        })
                    }
                }
            }
        }

        if (0 < troubleList.length) {
            let nowDt = new Date();
            let dt = Utilities.formatDate(nowDt, 'Asia/Tokyo', `MM/dd(${WEEKDAY[nowDt.getDay()]})`);
            let message = `\n今日の電車遅延だよ!!\n\n--- ${dt} ----\n\n`;
            for (let i in USER_LIST) {
                let user = USER_LIST[i];
                let userMessage = '';
                for (let j in user.routeList) {
                    let userRoute = user.routeList[j];
                    for (let k in troubleList) {
                        let trouble = troubleList[k];
                        if (trouble.route == userRoute) {
                            userMessage += `路線: ${trouble.route}\n`;
                            userMessage += `状況: ${trouble.status}\n`;
                            userMessage += `詳細: ${trouble.memo}\n`;
                            userMessage += `\n`;
                        }
                    }
                }
                if (0 < userMessage.length) {
                    message += `< ${user.name} >\n`;
                    message += userMessage;
                }
            }
            sendLineNotify(message);
        }

    } catch (e) {
        console.error(e.stack);
    }
}

/**
 * 運行情報を取得する
 */
function getOperationInfo() {
    let url = `https://transit.yahoo.co.jp/diainfo/area/${USER_REGION}/`;
    let options = {
        'method': 'get',
    };
    let response = UrlFetchApp.fetch(url, options);
    return response.getContentText('UTF-8');
}

/**
 * LINEにメッセージを送信する
 * @param {String} message メッセージ 
 */
function sendLineNotify(message) {
    let url = 'https://notify-api.line.me/api/notify';
    let options = {
        'method': 'post',
        'headers': {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            'Authorization': `Bearer ${LINE_NOTIFY_TOKEN}`
        },
        'payload': `message=${message}`
    };
    let response = UrlFetchApp.fetch(url, options);
    return JSON.parse(response.getContentText('UTF-8'));
}
```
データの抽出には、`Parser`ライブラリを使用しています。
`Parser.data(【対象のHTML】).from(【開始文字列】).to(【終了文字列】).build();`でページ情報から電車遅延情報を抽出しています。


# 参考リンク
- [LINE BOT で電車遅延検索お知らせ](https://qiita.com/k1_style/items/67e548959374e34ce751)
- [【GoogleAppsScript】【Slack】電車遅延情報post](https://qiita.com/H_Neco/items/937ecde84bde9c1c1710)
- [GoogleAppsScriptで路線ごとに電車の遅延情報をSlackに送信](https://qiita.com/naoya7076/items/cf739888dd2ce845bb5f)

# さいごに
ソースコードをGitHubに公開しています。

- [ソースファイルはこちら](https://github.com/yunbow/GoogleAppsScript-LINE-Train)

以上です。