NSEGアドベントカレンダーに参加して思い出したのですが、以前別のアドベントカレンダーでアルクマを追いかけていたことがありました*1*2。
- みんなのまちへ!アルクマキャラバン
- GoogleAppEngineとGoogleAppsScriptでアルクマを追いかける - メモ的な思考的な
- Google CloudSQLとGoogleAppsScriptのHTMLServiceでアルクマを追いかける - メモ的な思考的な
- GoogleDriveAPIでHTMLファイルを作成し、GoogleドライブでWebサイト公開してアルクマを追いかける - メモ的な思考的な
それらではGoogleのいくつかのサービスと組み合わせたものの、Google Apps Script(以下、GAS)だけを使って追いかけてはいませんでした。
そこで、今回思い出したついでに、GASだけでアルクマカレンダーをスクレイピングして地図に表示してみました。
処理の流れ
流れは
- Chromeなどのブラウザで、GASで作ったWebページのエントリポイントへアクセス
- GASで、アルクマスケジュールのサイトをスクレイピングし、日時・イベント名・場所を取得
- GASで、場所と
Maps.newGeocoder().geocode()
を使って、緯度・経度を取得 - GASで、緯度・経度と
Maps.newStaticMap()
を使って、地図画像を取得 - GASで、地図画像を含むHTMLをブラウザに返す
のような感じにします。
なお、GASで実装する場合、
- 使えるGoogle Mapsは、Static Mapのみ
- HTMLにはいろいろと制限あり
- ブラウザでソースコードを確認すると読めない感じのソースになっていたり
- Geocoding APIには一日の使用回数制限あり
の制限などがあるものの、今回の目的は達成できそうでした。
実装
Webからのエントリポイント
doGet()
にて、用意したHTMLテンプレートを返します。
なお、前回以降に変更が入ったようで、現在では.setSandboxMode(HtmlService.SandboxMode.IFRAME)
が必要です。
HTML Service: Create and Serve HTML | Apps Script | Google Developers
function doGet(){ var output = HtmlService.createTemplateFromFile("index"); return output.evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME); }
用意したHTMLテンプレートは以下のような感じで、その中で、
- getEvents()
- getMap()
の2つの自作のGAS関数を呼び出しています。
また、CSS3のFlexboxも使えるようだったので、<style>
にて使っています。
これからのCSSレイアウトはFlexboxで決まり! | Webクリエイターボックス
なお、以下のBest Practicesに従い、不要な<html>
、<head>
、<body>
などのタグは削除しました。見た感じ、確かに削除しても正常に動作しています。
HTML Service: Best Practices | Apps Script | Google Developers
<!DOCTYPE html> <title>アルクマップ - GAS版</title> <style> .day { color: blue; } .event { margin-bottom: 10px; } .block{ display: flex; } </style> <div id="info" class="block"> <div id="schedule"> <h3>アルクマスケジュール</h3> <!-- GASのgetEvents()を呼び出して、戻り値をもとにHTMLを組み立てる --> <? var events = getEvents(); for(var i = 0; i < events.length; i++){ var day = events[i].day; output.append('<div class="event">'); output.append('<div class="day">' + day + '</div>'); output.append('<div class="title">' + events[i].title + '</div>'); output.append('<div class="place">' + events[i].place + '</div>'); output.append('</div>'); } ?> </div> <div id="map" class="block"> <!-- GASのgetMap()で作成したGoogle StaticMapを表示する --> <div> <img src="<?= getMap(); ?>" alt="map"> </div> </div> </div>
スクレイピング
アルクマスケジュールに対し、
という形のスクレイピングを行い、必要な情報を取得しています。GASの場合は力技な印象です。
function getEvents() { // アルクマのスケジュールにアクセス var response = UrlFetchApp.fetch("http://www.arukuma.jp/caravan/index.php"); // 当月のスケジュール部分を取得 var reg = /<div class="schedule aug">([\s\S]*?)<\/div>/i; var match = reg.exec(response.getContentText()); var content = match[1]; // 正規表現による置換で、スケジュール部分を整形してゆく // 正規表現で扱いやすくするために、改行とスペースを削除 content = content.replace(/\s/g, "") ...
Static Mapやジオコーディング部分
昔作った時と変わらなかったので、そのまま流用しています。
デモサイト
現時点だとこんな感じです*3。
ソースコード
GitHubに上げました。
Googleドライブにスクリプトプロジェクトを作成して、.gs
と.html
をコピペすれば動作するかと思います。
thinkAmi/ArukuMapGAS