LoginSignup
6
1

More than 3 years have passed since last update.

位置情報を送ると近くの宿泊施設を返すLINEBotを作る

Posted at

初めに

LINEmessagingAPI + WebAPIで、位置情報を送ると近くの宿泊施設を返してくれるLINEBotを作成しました。
ついでに最寄り駅も返します。

利用したAPI
■楽天トラベル施設検索API(宿泊施設の検索)
https://webservice.rakuten.co.jp/api/simplehotelsearch/

■HeartRails Geo API(最寄り駅の検索)
http://geoapi.heartrails.com/

コード

'use strict'; // おまじない

// ########################################
//               初期設定など
// ########################################

// パッケージを使用します
const express = require('express');
const line = require('@line/bot-sdk');
const axios = require('axios');

// ローカル(自分のPC)でサーバーを公開するときのポート番号です
const PORT = process.env.PORT || 10000;

// Messaging APIで利用するクレデンシャル(秘匿情報)です。
const config = {
    channelSecret: '作成したBotのチャネルシークレット',
    channelAccessToken: '作成したBotのチャネルアクセストーク'
};



// ########## ▼▼▼ サンプル関数 ▼▼▼ ##########
const sampleFunction = async (event) => {
    // ユーザーメッセージが位置情報かどうか
    if (event.message.type == 'location') {
        let pushText = '';
        const latitude = event.message.latitude;
        const longitude = event.message.longitude;
        const postNumber = event.message.address.split('')[1].split(' ')[0].replace('-','');

        //楽天トラベル施設検索APIで、指定された位置情報から半径1km以内の宿を検索(おすすめ順・5件)
        client.pushMessage(event.source.userId, {
            type: 'text',
            text: '1km以内の宿泊施設を検索します。',
        });
        try {
            const rakuten = await axios.get('https://app.rakuten.co.jp/services/api/Travel/SimpleHotelSearch/20170426?applicationId=アプリID&format=json&latitude=' + latitude + '&longitude=' + longitude + '&searchRadius=1&datumType=1&hits=5');
            for(let i in rakuten.data.hotels){
                client.pushMessage(event.source.userId, {
                    type: 'text',
                    text: rakuten.data.hotels[i]['hotel'][0]['hotelBasicInfo']['hotelInformationUrl'],
                });
            }
        } catch (error) {
            pushText = '楽天検索中にエラーが発生しました。ごめんね。';
            // APIからエラーが返ってきたらターミナルに表示する
            console.error(error);
            client.pushMessage(event.source.userId, {
                type: 'text',
                text: pushText,
            });
        }

        //郵便番号から最寄駅を検索
        try {
            const station = await axios.get('http://geoapi.heartrails.com/api/json?method=getStations&postal=' + postNumber);
            client.pushMessage(event.source.userId, {
                type: 'text',
                text: '最寄り駅は' + station.data['response']['station'][0].name + '駅です。',
            });
        } catch (error) {
            pushText = '最寄り駅検索中にエラーが発生しました。ごめんね。';
            // APIからエラーが返ってきたらターミナルに表示する
            console.error(error);
            client.pushMessage(event.source.userId, {
                type: 'text',
                text: pushText,
            });
        }
        return await client.pushMessage(event.source.userId, {
            type: 'text',
            text: '良い旅を。',
        });
    }
};
// ########## ▲▲▲ サンプル関数 ▲▲▲ ##########



// ########################################
//  LINEサーバーからのWebhookデータを処理する部分
// ########################################

// LINE SDKを初期化します
const client = new line.Client(config);

// LINEサーバーからWebhookがあると「サーバー部分」から以下の "handleEvent" という関数が呼び出されます
async function handleEvent(event) {
    // 受信したWebhookが「テキストメッセージ以外」であればnullを返すことで無視します
    //if (event.type !== 'message' || event.message.type !== 'text') {
    //    return Promise.resolve(null);
    //}
    // サンプル関数を実行します
    return sampleFunction(event);
}



// ########################################
//          Expressによるサーバー部分
// ########################################

// expressを初期化します
const app = express();

// HTTP POSTによって '/webhook' のパスにアクセスがあったら、POSTされた内容に応じて様々な処理をします
app.post('/webhook', line.middleware(config), (req, res) => {
    // Webhookの中身を確認用にターミナルに表示します
    console.log(req.body.events);

    // 検証ボタンをクリックしたときに飛んできたWebhookを受信したときのみ以下のif文内を実行
    if (req.body.events[0].replyToken === '00000000000000000000000000000000' && req.body.events[1].replyToken === 'ffffffffffffffffffffffffffffffff') {
        res.send('Hello LINE BOT! (HTTP POST)'); // LINEサーバーに返答します
        console.log('検証イベントを受信しました!'); // ターミナルに表示します
        return; // これより下は実行されません
    }

    // あらかじめ宣言しておいた "handleEvent" 関数にWebhookの中身を渡して処理してもらい、
    // 関数から戻ってきたデータをそのままLINEサーバーに「レスポンス」として返します
    Promise.all(req.body.events.map(handleEvent)).then((result) => res.json(result));
});

// 最初に決めたポート番号でサーバーをPC内だけに公開します
// (環境によってはローカルネットワーク内にも公開されます)
app.listen(PORT);
console.log(`ポート${PORT}番でExpressサーバーを実行中です…`);

結果

実行結果です。

image.png

課題・考察

・最寄り駅の取得ができない場合がある
原因:LINEで位置情報を送る際、施設を指定すると郵便番号が送られない
対策:住所情報→郵便番号変換→最寄り駅検索の処理に変更する

・対話型で検索条件をより柔軟にしたい
楽天トラベル施設検索APIを利用する際、検索条件は「おすすめ順」で5件表示としていますが、
Botとの会話で「値段が安い順」などを設定して検索できればより使いやすいなと感じました。

位置情報を利用したAPIは他にもいくつもあるので、さらに組み合わせるともっと便利なBotになる気がします。
宿検索してそのまま予約までできるんじゃないかな。

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1