あるサイトのナビゲーションの内容が変わったら知りたいと思う事があったので、採用した手段と調べた事を残しておきます。
今回の要件
- サーバーサイドで実行したい
- 1日1回実行したい
- 1URLのみを対象とする
- ナビゲーションの内容と項目数を知りたい
- お金はかけたくない
- 手軽に済ませたい
- 結果を通知したい
結論
いくらか調べたのですが、結局
- GASを時間ベースのトリガーで実行して
- URLをFetchして取得したHTML文字列を
- 正規表現で必要な部分のみ抽出し
- Gmailで結果を送信する
ことにしました。
候補手段
頭に浮かんだのは下の手段でした
- スクレイピングサービス
- AWS Lambda
- GAS
スクレイピングサービス
はじめは、こちらのサービスの無料プランで試そうとしたのですが、14日間の無料トライアルの後、自動的に有料プランに移行されるらしく、今回の要件に合わないのでやめました。
解約もすんなりいかずに精神的に消耗したので、サービスを探すのはやめました。
AWS Lambda
できるのはわかってますが、お手軽に済ませたいのでスキップしました。
GAS
トリガーがあり、Gmailも簡単に送れて良さそうなので、今回はGASを使う事にしました。
GASで特定の要素を取得する候補手段
HTMLを取得する部分と、Gmailを送信する部分はサンプル通りに1行書けば良いだけでした。
HTMLから必要な要素をいかにして取り出すかで、少し考える事になりました。
XMLをパースして1階層ずつたどっていく
rootDoc.getChild('Body', nsSoapenv).getChild('loginResponse', ...
GASの標準機能でセオリーっぽいのですが、1階層ずつ指定していくのは嫌なので採用しない事にしました。
IMPORTXML
spreadsheetのimportxml関数で必要な要素を取得した上で、GASで残りの処理をするというアイデアですが、どうせならGASだけで完結させたいので採用しない事にしました。
querySelectorAllのような機能
ブラウザのJavaScriptなら、selectorを使えば欲しい要素が簡単に取得できるのですが、GASでそれを実現する機能は用意されていないようでした。
querySelectorAllのPolyfillをGASにもってくる
IE7程度のdocumentオブジェクトが利用できる事が前提のようなので、GASに流用するのは無理でした。
getElementsByClassNameのGASによる実装例
対象のXMLが壊れているらしく XmlService.parse(html);
の行でエラーになりました。
このサイトに対してはXMLのパースが必要な手段は通用しなさそうです。
独自のgetElementByClassNameライブラリ
こちらもXMLのパースが必要なので、今回は利用できなさそうです。
独自のParserライブラリ
場合によっては有用かもしれないのですが、今回やりたい事程度なら記述量もさほど変わらないので正規表現を使った文字列抽出でいいやという気になりました。
実装例
function myFunction() {
var html = UrlFetchApp.fetch(url).getContentText();
var reg = /<div class="box">([\s\S]*?)<\/div>/g;
var text = html.match(reg);
MailApp.sendEmail(mailAddr, mailTitle, text.join("\n"));
}
まとめ
迷う事なく今回の手段を講じていれば、手軽に実現できたと言えるのではないかと思います。
ただ、必要な要素の抽出が泥臭い感じになって残念感があるので、よりスマートな手段を見つけられたらいいなと思います。