この記事はN高等学校 Advent Calendar 2019の最終日です。
こんにちは。N高等学校2年の0505Keitanと申します。
クリスマスなので今回はディズニーの待ち時間をLINEで見れるようにしたことでも書こうかと思います。
他にも色々作ってるんですけどいい感じに記事にできるやつがなかったのでこれにしました(
ちなみに紹介記事なので作ってみよう系じゃないです。
作ったもの
以下の画像のように待ち時間を垂れ流します。
ちなみに公開はしないです。結構ガバガバ実装なので...。
なお、他にもショーの時間とかも見れるようになってます。詳しくはコチラ。
データ取得先なんですけど、ディズニーは待ち時間APIを出していない(当たり前)なので、tokyodisneyresort.infoの情報を使わせていただくことにしました。このサイトに10分に一回(7分間隔)アクセスし、スクレイピングして更新、表示させます。
念のためサーバーに過負荷を掛けさせないため、要求ごとに取得させるのではなく、取得したデータを一度スプレッドシートに保存し、メッセージごとに呼び出しています。
使用技術
- Google Apps Script
- Google Spreadsheet
- Parser
- Moment
実行フローとしては
① tokyodisneyresort.infoにアクセス
② 取得データを整形して、Googleスプレッドシートに保存
③ LINEからWebhookでリクエストが飛んでくる
④ スプレッドシートに情報を取りに行く
⑤ データをGASに渡す
⑥ GASからLINEに送信する
という順番です。
GASのライブラリ
今回は取得したhtmlをパースしてくれるParser
と日付の処理を簡単にしてくれるmoment
を利用しています。
導入はGASの編集画面からリソース
→ライブラリ
→Add a libraryの欄に以下のプロジェクトキーを入力して追加をクリック!
- Parser
M1lugvAXKKtUxn_vdAG9JZleS6DrsjUUV
- Moment.js
MHMchiX6c1bwSqGM1PZiW_PxhMjh3Sh48
コード
結構長くて処理複雑なので主要部分だけ書きます。
ランドとシーのスタンバイ時間を配列で出す。
var response = UrlFetchApp.fetch('https://tokyodisneyresort.info/realtime.php?park=land&order=name', {'validateHttpsCertificates' : false});
var response_c = UrlFetchApp.fetch('https://tokyodisneyresort.info/realtime.php?park=sea&order=name', {'validateHttpsCertificates' : false});
var html = response.getContentText('UTF-8');
var html_c = response_c.getContentText('UTF-8');
var data = Parser.data(html).from('<div class="attr_name">').to('</div>').iterate();
var data_c = Parser.data(html_c).from('<div class="attr_name">').to('</div>').iterate();
var fdata = Parser.data(html).from('<div class="attr_wait">').to('</div>').iterate();
var fdata_c = Parser.data(html_c).from('<div class="attr_wait">').to('</div>').iterate();
for(i=0;i<data.length;i++){
data[i]=data[i].replace(/ /g,'').replace('&park=land">','').replace('</a>','').replace('<span class="new">NEW</span>','').replace('amp;','').replace(/\n/g,'').replace(/ /g,'');
fdata[i]=fdata[i].replace(/<span class="fp">【FP:(TICKETING|TICKETING_END|NOT_TICKETING_TODAY)】<\/span>/g,'(FP対象)').replace(/<span class="greeting_timetable">/g, '').replace(/<\/span>/g, '').replace(/ /g,'').replace(/\n/g,'').replace(/<br\/>/g,'\n').replace(/分/g,'分').replace(/ /g, '').replace(/^$/g, '情報なし');
data[i]='【'+data[i]+'】\n'+fdata[i]+'\n\n';
}
for(i=0;i<data_c.length;i++){
data_c[i]=data_c[i].replace(/ /g,'').replace('&park=sea">','').replace('</a>','').replace('<span class="new">NEW</span>','').replace('amp;','').replace(/\n/g,'').replace(/ /g,'');
fdata_c[i]=fdata_c[i].replace(/<span class="fp">【FP:(TICKETING|TICKETING_END|NOT_TICKETING_TODAY)】<\/span>/g,'(FP対象)').replace(/<span class="greeting_timetable">/g, '').replace(/<\/span>/g, '').replace(/ /g,'').replace(/\n/g,'').replace(/<br\/>/g,'\n').replace(/分/g,'分').replace(/ /g, '').replace(/^$/g, '情報なし');
data_c[i]='【'+data_c[i]+'】\n'+fdata_c[i]+'\n\n';
}
LINEへ送信
function reply(message, token) {
UrlFetchApp.fetch(line_endpoint, {
'headers': {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer ' + CHANNEL_ACCESS_TOKEN,
},
'method': 'post',
'payload': JSON.stringify({
'replyToken': token,
'messages': [{
'type': 'text',
'text': message,
}],
}),
});
return;
}
LINEでレスポンスをするにはdoPost
に含まれているreplyToken
を指定しなければなりません。
問題点と改善結果
①22:00以降は結果が同じになる
実行しても同じ結果なので22:00以降は各処理前に時間を取得してreturnさせました。(もっといい方法があるはず)
if(Moment.moment().format('HH')>=22||Moment.moment().format('HH')<08){
sheet_standby.getRange('A1').setValue('東京ディズニーリゾートは現在閉園中です。');
sheet_standby.getRange('B1').setValue('東京ディズニーリゾートは現在閉園中です。');
sheet_standby.getRange('A2:B2').setValue('最終取得時間:'+Moment.moment().format('HH:mm'));
return;
}
②GASでアクセスするときSSLエラーが出る
(あまりいい方法ではないが)
無理やりアクセスさせるためにUrlFetchApp
に{'validateHttpsCertificates' : false}
をつけました。
UrlFetchApp.fetch('https://tokyodisneyresort.info/realtime.php?park=land&order=name', {'validateHttpsCertificates' : false});
まとめ
やっぱりGASはいいですよね(あとディズニー)!!!
ぜひ公式API出して欲しいです。
実装もすぐに終わるのでGASはぜひ使いましょう!!!本当に便利です。
ガバガバ実装なの許してくださいなんでもしますから