酒とITと私

GASでYahooニュースのスクレイピング

Google Apps Scriptを使って、特定キーワードのニュースをYahooニュースから抜いてきてLINE Notifyに通知する、というものを作りたいと思います。

GASの使い方、LINE Notifyの設定方法などはこちら「Google Calendarの予定を毎朝LINEに送る」をご覧ください。

スポンサーリンク

構成

スプレッドシートに登録されているキーワードの一覧に従って、Yahooニュースの検索を行い、キーワード毎にLINEに通知する、というものを作ります。スプレッドシートは単独でも構いませんが、今回はアンケートフォームから登録できるようにしています。

アンケート作成

アンケートはガチで単純で構いません笑

僕の場合はこんな感じで、記述式の回答欄が一つだけのものを作成しました。

準備

いくつか準備をします。

ライブラリの導入

Yahooニュースから取得したhtmlを解析するためのライブラリを導入します。

スクリプトエディターのリソース>ライブラリをクリックします。

サブウィンドウが現れますので、「1Mc8BthYthXx6CoIz90-JiSzSafVnT6U3t0z_W3hLTAX5ek4w0G_EIrNw」を入力し、「追加」をクリックします。

設定画面が出てきますので、バージョンは最新のものを選んで、デベロッパーモードを有効にしましょう。

スプレッドシートのID取得

まずはスプレッドシートを作成して、URLの下記の黄色くなっている部分が、スプレッドシートのIDになります。後で使うのでコピーしておきます。

スクレイピングするコード

ソースコードはこんな感じです。

// line notifyのトークン
var lineToken = "LINE notifyのトークンを設定する";

// 最新ニュースかどうかの判断に必要
var date = new Date();

// キーワードが登録されているスプレッドシートのid
var spreadsheet = SpreadsheetApp.openById('スプレッドシートのid');

function myFunction() {
 var prop = PropertiesService.getScriptProperties().getProperties();
 
 // スプレッドシートの1シート目取得
 var sheet = spreadsheet.getSheets()[0];
 
 // B1列取得
 var cell = sheet.getRange("B1");
 
 // B1列の値を取得
 var firstRowValues = cell.getValues();
 
 // B1列の1行目(項目名)取得
 var titleColumns = firstRowValues[0];

// 2行目以降(キーワード)を取得
 var lastRow = sheet.getLastRow();
 var rowValues = [];
 for(var rowIndex=2; rowIndex<=lastRow; rowIndex++) {
 var colStartIndex = 2;
 var rowNum = 1;
 var range = sheet.getRange(rowIndex, colStartIndex, 
                            rowNum, sheet.getLastColumn());
 var values = range.getValues();
 rowValues.push(values[0]);
 }
 
 // スプレッドシートに登録したキーワードでYahooニュースを検索、LINEへ送る、のループ
 rowValues.forEach( function searchWord( word ) {
 
 // キーワードが日本語を含んだりするときのためのURLエンコード
 var encoded = encodeURIComponent(word);
 var text = "";
 text += '\n' + text + word + '\n';
 
 // 検索のURL
 var url = 'https://news.yahoo.co.jp/search/'
 + '?ei=UTF-8&aq=-1&ai=0FhK6io5Rl.OgYUBY1xjLA&ts=2425&p='
 + encoded + '&meta=vc%3D&fr=sfp_as';
 
 // 取得したHTMLから欲しい部分を抜き出す作業
 // 上記URLのページを取得し、htmlをテキストで抜き出す 
 var html = UrlFetchApp.fetch(url).getContentText();
 
 // 検索結果に出ている各記事のテキスト取得
 var doc = Parser.data(html)
 .from('<div id="contents" role="main">')
 .to('<hr class="separation">')
 .build();
 
 // 記事へのリンク取得
 var as = Parser.data(doc)
 .from('<a href="')
 .to('"')
 .iterate()
 
 // 広告は除外
 as = as.filter(function(v){
 return (v.indexOf("https://headlines.yahoo.co.jp/") !== -1);
 });
 
 // 記事名取得
 var names = Parser.data(doc)
 .from('<p class="a">')
 .to("</p>")
 .iterate()
 
 // 検索結果に表示されている記事のリード文章取得
 var descs = Parser.data(doc)
 .from('<span class="ct1">')
 .to("</span>")
 .iterate()
 
 // 日付取得
 var dueDate = Parser.data(doc)
 .from('<span class="d">')
 .to("</span>")
 .iterate()
 
 // 今日の日付を基に、最新のニュースのみ取り出す処理
 for(i=0;i<as.length;++i){
 if (dueDate[i].indexOf((date.getMonth() +1 ) + "月" + date.getDate() + "日") 
     != -1 || dueDate[i].indexOf((date.getMonth() +1 ) 
     + "月" + (date.getDate() -1 ) + "日") != -1) {
 text = text + (i+1) + "\nURL:" + as[i] + "\n" 
 + names[i] + "\n" + descs[i] + "\n";
 }
 }
 
 if (text=="") {
 text = "ない";
 }
 
 // 送信
 // 該当ニュースがない場合は、ここ自体を飛ばしてもよい
 sendToLine(text);
 
 });
 
}

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);
}

実装は以上です!これで、トリガーを設定すれば、決まった時間にニュースを届けてくれます!