先日「スクレイピング」という技術があることを知りまして(聞いたことはあったけどどんなものか理解してなかった)。
世間的にはpythonで書くようなんですけど、pythonをローカル環境以外で動かす方法を知らないんですよね。(ローカルのスクリプトだとマシンがネットにつながってない時間は実行できない)
こんなときに便利なのがGoogleAppsScriptです。どうやらスクレイピングもできるようなので、早速やってみました。
GoogleAppsScript(GAS)とは
簡単に言えば、Googleのクラウド上で動くJavaScriptです。Googleドライブ上にコードを作成するので、web上で実行してくれます。トリガーを毎日22-23時などと時間で設定しておけば、webサーバー建てなくても定期的に実行できます。便利。
スクレイピングとは
プログラムを用いてwebサイトから情報を抽出してくることです。やろうと思えば大量のデータを取得することができるので、サイトの利用規約などに違反しないように注意する必要があります。
やってみた
今回は日テレの番組表のページから「金曜ロードSHOW」の情報を取ってきて、毎週木曜にラインで通知させるようにしてみます。
日テレの番組表のhtmlソースから金曜ロードSHOWの内容を取ってくるプログラムを作り、それをGASの機能で毎週木曜に実行するという形です。
プログラムの中身は、UrlFetchApp.fetch(url)
でurl
の情報を受け取り、getContentText('UTF-8')
でテキスト情報として取得するだけです。簡単! UrlFetchApp
はGAS特有のライブラリです。
文字列として扱えるので、あとは切り取ったり置換したり好きにしてくれ。
大事な部分だけ抽出するとこんな感じ。
function myFunction () {
var url = 'http://www.ntv.co.jp/program/';
var response = UrlFetchApp.fetch(url);
var html = response.getContentText('UTF-8');
// ---------- 欲しい領域の取得 ----------//
// 要は検索して切り取ってるだけ
var titleSearchTag_head = '金曜ロードSHOW!';
var headIndex = html.indexOf(titleSearchTag_head);
Logger.log(headIndex);
/// タイトルの取得
var titleSearchTag_foot = '<img alt="字幕放送"';
if (headIndex !== -1) {
var tmp = html.substring(headIndex + titleSearchTag_head.length);
var footIndex = tmp.indexOf(titleSearchTag_foot)
if (footIndex !== -1) {
var title = tmp.substring(0, footIndex/* + titleSearchTag_foot.length*/);
}
else {
Logger.log("foot index error")
}
}
else {
Logger.log("head index error");
}
/// 説明文の取得
var detailSearchTag_head = '<p>';
var detailSearchTag_foot = '</p>';
var headIndex = tmp.indexOf(detailSearchTag_head);
Logger.log(headIndex);
if (headIndex !== -1) {
var detail = tmp.substring(headIndex + detailSearchTag_head.length);
var footIndex = detail.indexOf(detailSearchTag_foot);
if (footIndex !== -1) {
Logger.log(footIndex);
detail = detail.substring(0, footIndex/* + detailSearchTag_foot.length*/);
Logger.log(detail);
}
else {
Logger.log("foot index error")
}
//////////
// ここで title と detail をLINEトークなどに送信
//////////
}
else {
Logger.log("head index error");
}
}
以下がフルバージョン。LINEに送る方法や、GASのトリガー設定の説明は省略。
function myFunction () {
var lineToken = XXXXXXXXXX; //トークごとに設定されるトークン
var url = 'http://www.ntv.co.jp/program/';
var response = UrlFetchApp.fetch(url);
var html = response.getContentText('UTF-8');
// 特殊文字の置換
html = html.replace(/&/g, '&');
// ---------- 欲しい領域の取得 ----------//
// 要は検索して切り取ってるだけ
var titleSearchTag_head = '金曜ロードSHOW!';
var headIndex = html.indexOf(titleSearchTag_head);
Logger.log(headIndex);
/// タイトルの取得
var titleSearchTag_foot = '<img alt="字幕放送"';
if (headIndex !== -1) {
var tmp = html.substring(headIndex + titleSearchTag_head.length);
var footIndex = tmp.indexOf(titleSearchTag_foot)
if (footIndex !== -1) {
Logger.log(footIndex);
var title = tmp.substring(0, footIndex);
Logger.log(title);
}
else {
Logger.log("foot index error")
}
}
else {
Logger.log("head index error");
}
/// 説明文の取得
var detailSearchTag_head = '<p>';
var detailSearchTag_foot = '</p>';
var headIndex = tmp.indexOf(detailSearchTag_head);
Logger.log(headIndex);
if (headIndex !== -1) {
var detail = tmp.substring(headIndex + detailSearchTag_head.length);
var footIndex = detail.indexOf(detailSearchTag_foot);
if (footIndex !== -1) {
Logger.log(footIndex);
detail = detail.substring(0, footIndex/* + detailSearchTag_foot.length*/);
Logger.log(detail);
}
else {
Logger.log("foot index error")
}
// ラインに送るテキストの作成
var header = "\n明日は金曜日です。金曜ロードSHOWは\n\n";
var footer = "\n\nです。";
sendToLine(header + title + "\n" + detail + footer);
}
else {
Logger.log("head index error");
}
//---------- tools ----------//
function sendToLine(text){
var token = lineToken;
var options =
{
"method" : "post",
"payload" : "message=" + text,
"headers" : {"Authorization" : "Bearer "+ token}
};
UrlFetchApp.fetch("https://notify-api.line.me/api/notify", options);
}
}
送られる内容はこんな感じになります(2018/10/05の内容)。
明日は金曜日です。金曜ロードSHOWは
特別エンターテインメント『ウケる!偉人伝』林修&羽鳥慎一
みやぞん・友近×ゆりやん・ロバート・ブルゾンちえみ・ザキヤマ×竹山・オードリー・野性爆弾くっきー総勢22名の人気芸人が偉人になりきって熱演!笑って学べる2時間!
です。
今後
確かに簡単なんですけど、これが簡単なのは静的なwebサイトだからなんですよね。
js使って動的に生成される(つまりソースコードだけでは該当の情報が書いてない)場合は難しそうなので、今後の課題としたいと思います。