【GAS】定期的にスクレイピングを実行して結果をスプシに書き出す
スクレイピング処理のGASコードを定期的(日次)実行して、結果をプレッドシートに書き出してみたいと思います。
スクレイピング処理用の関数を用意
前回記事では、【順位】【タイトル】【URL】【カテゴリ】をリスト化してconsole.logしてました。今回は記述を少し修正し、スクレイピング実行の関数を呼び出せば上記の値の組み合わせリストが戻り値として返ってくるようにしています。
function getYahoonews() {
var response = UrlFetchApp.fetch("https://news.yahoo.co.jp/");
var text = response.getContentText("utf-8");
//トップニュースのブロックを抽出
var topic_block = Parser.data(text).from('class="sc-ekHBYt ckuddT">').to('</div>').build();
//ulタグで囲まれている記述(トップニュース)を抽出
var content_block = Parser.data(topic_block).from('<ul>').to('</ul>').iterate();
// 記事リスト用の変数を宣言
var list=[];
// content_blockの要素数分繰り返し(今回は1回)
for (var i = 0; i < content_block.length; i++) {
// content_blockの要素のうち、aタグに囲まれている記述を抽出
topicks = Parser.data(content_block[i]).from('<a').to('</a>').iterate();
// aタグに囲まれた記述の回数分、タイトルとURLを抽出する
for(var j = 0; j < topicks.length; j++){
var topick = topicks[j];
//URL取得
var topick_url = topick.replace(/.*href="/,"").replace(/".*/,"");
//タイトル取得
var topick_title = topick.replace(/.*class="sc-frDJqD bJCuGd">/,"").replace(/<.*>/,"");
//リスト格納
// 各ニュースページからカテゴリを取得
var response_topick = UrlFetchApp.fetch(topick_url);
var text_topick = response_topick.getContentText("utf-8");
var topick_category = Parser.data(text_topick).from('トピックス(').to(')').build();
// ニュース順位、URL、タイトル、カテゴリーを取得
list.push([j+1,topick_url,topick_title,topick_category]);
// Logger.log(Parser.data(content).from('<li').to('</li>').iterate());
}
}
return list;
}
対象のページ構成や取得したい情報によって配列の形は変わりますが、スクレイピング用の実行コードは独立した関数で記述しておき、別の関数から呼び出した時に戻り値として返っておくようにしておくと全体のコードを書きやすいです。
さて、別の関数から呼び出してリストに記事一覧が格納されていることを確認しておきます。
//トップニュースのリスト
var list = getYahoonews();
Logger.log(list);
[[1.0, https://news.yahoo.co.jp/pickup/6410874, 水際対策強化 28日に3カ国追加, 国内], [2.0, https://news.yahoo.co.jp/pickup/6410871, 計36道県で「会食制限なし」に, 国内], [3.0, https://news.yahoo.co.jp/pickup/6410868, 維新代表選実施せず 松井氏続投, 国内], [4.0, https://news.yahoo.co.jp/pickup/6410882, リニア工事事故 掘削再開できず, 地域], [5.0, https://news.yahoo.co.jp/pickup/6410870, LOOKチョコ 当初と違う今の4味, 経済], [6.0, https://news.yahoo.co.jp/pickup/6410883, 25秒でKO 元西武相内が初勝利, スポーツ], [7.0, https://news.yahoo.co.jp/pickup/6410881, 速報日本Sオリックス対ヤクルト, スポーツ], [8.0, https://news.yahoo.co.jp/pickup/6410879, THE W 芸歴0年のトリオ決勝へ, エンタメ]]
問題なさそうですね!
書き出し用のスプレッドシートを用意
続いてリストを格納するスプレッドシートを用意します。読者のみなさんがスクレイピングで取得/書き出したい情報に合わせて列を作っておきましょう。本記事ではリストに入れた値に実行日付を加え、予め5つの列を作っておきます。
後で出力先のシートを指定できるように、列を追加したシートに「daily_data」という名前を付けておきました。また、のちほどのコードで使うためにファイルのIDをコピーしておきます。
スプシ書き出し用のコードを用意
今回のコードの全体像を先に記載します。
function myFunction() {
//トップニュースのリスト
var list = getYahoonews();
// 書き出し先のスプレッドシート
var id = "[ファイルのidを入れる]";
var ss = SpreadsheetApp.openById(id);
var sheet = ss.getSheetByName("daily_data"); // シート名で指定
// 今日の日付
var date = new Date();
date = Utilities.formatDate(date, 'Asia/Tokyo', 'yyyy/MM/dd');
// 空欄になっている行から挿入するため最終行を取得
var lastRow = sheet.getLastRow();
// リストの配列数分スプレッドシートに追加
for(var i=0; i < list.length; i++){
sheet.getRange(lastRow+1+i,1).setValue(date);
sheet.getRange(lastRow+1+i,2).setValue(list[i][0]);
sheet.getRange(lastRow+1+i,3).setValue(list[i][1]);
sheet.getRange(lastRow+1+i,4).setValue(list[i][2]);
sheet.getRange(lastRow+1+i,5).setValue(list[i][3]);
}
}
ニュース一覧をリスト変数として保持
スクレイピングの実行結果を返り値としてlistという変数に格納します。
//トップニュースのリスト
var list = getYahoonews();
書き出し先のスプレッドシートを指定
GASで書き出し先スプレッドシートを指定します。記述方法は複数ありますが、下記ではスプレッドシートをidで指定して、その中に用意した<daily_data>というシート名で書き出し先シートを指定しました。
// 書き出し先のスプレッドシート
var id = "スプレッドシートのID";
var ss = SpreadsheetApp.openById(id);
var sheet = ss.getSheetByName("daily_data"); // シート名で指定
実行日を取得
○年○月〇日のトップニュースがこれ、というデータを持っておきたいので、実行する日付を取得します。
// 今日の日付
var date = new Date();
date = Utilities.formatDate(date, 'Asia/Tokyo', 'yyyy/MM/dd');
スプシに書き出していく
定期的に処理を実行する予定なので、前日には複数行記述されていることを想定し、書き出しは空欄ではない最終行の次の行から行っていきます。
// 空欄になっている行から挿入するため最終行を取得
var lastRow = sheet.getLastRow();
// リストの配列数分スプレッドシートに追加
for(var i=0; i < list.length; i++){
sheet.getRange(lastRow+1+i,1).setValue(date);
sheet.getRange(lastRow+1+i,2).setValue(list[i][0]);
sheet.getRange(lastRow+1+i,3).setValue(list[i][1]);
sheet.getRange(lastRow+1+i,4).setValue(list[i][2]);
sheet.getRange(lastRow+1+i,5).setValue(list[i][3]);
}
今回のスクリプトでは、最終行数を指定するためにgetLastRowメソッドを使っています。getLastRowメソッドについては下記の記事で詳しく解説しています。
実行結果
とても良い感じですね。
定期的なトリガーを設定する
1日に一回このコードを走らせて記事ログを蓄積できるように、トリガーを設定します。
コード記述画面に時計マークがトリガー設定です。
「トリガーを追加」から「myFunction」を「日付ベースのタイマー」で「午後12時~1時」に走らせるように設定しました。
実行結果
数日間データの蓄積を続けてみたところ、特にエラーも起きずに毎日12時~13時の間に処理を実行してくれていました。
これで、Yahoo!ニューストップのサイト構造が変わらなければ、取得し続けてくれるはずです。
また、試しにカテゴリシェアの推移を見てみました。特にどのカテゴリが優位などはなく(しいて言うならエンタメは毎日出現)、バランスよく取り上げられているようです。
お昼と夜とで比べてみたり、長期でデータをためて週次で推移を追ってみるのも面白そうですね。
まとめ
今回は、GASを使ってスクレイピングを定期的に自動実行して結果をスプ氏に書き出す方法を解説しました。
- スクレイピング実行結果を返り値とした関数を用意
- 実行結果のデータに合わせ、列を予め作成したスプレッドシートを用意
- スプレッドシートのIDを指定して、実行結果を書き出し
- スクリプト実行日を取得してデータに含めておくと後から分析しやすい
- エディタ上のタブからトリガーを選択して発火条件を設定
↓他のスクレイピングに関する解説記事