サイト名変更・お引越しのお知らせ

【GAS】Google Apps ScriptでRSSリーダーを作成する方法を解説

Google Apps Script(以下GAS)でRSSリーダーを作成する方法を解説します。

SpreadSheetでデータを取得したいURLを追加して、その情報を定期取得するように実装していきます。

モグモグさん

GASを使うことで、データの永続化や定期実行ができる点がメリットです!

ちなみにRSSリーダーで有名なサービス(アプリ)にFeedlyというものがありますので、知らない方はチェックしてみてください。

補足

本記事では、RSS2.0に対応するように実装しています。

RSS1.0やATOMには対応していませんが、記事内で補足はしています。

SpreadSheetに対象サイトのURLを追加

まずは対象とするサイトのURLを追加していきます。

対象サイトのRSSURL

まずはSpreadSheetを作成しましょう。

タブ(シート)の名前は、feedsとしました!

本記事では、YahooとITmediaのフィードURLを追加しました!

  • https://news.yahoo.co.jp/rss/topics/top-picks.xml
  • https://rss.itmedia.co.jp/rss/2.0/itmedia_all.xml

ちなみにフィードのURLを見つけるにはこういったサービスを使うと楽に見つけることができます。

GASでデータを取得

それでは追加したサイトのデータをGASで取得していきましょう。

GASの準備

GASメニュー

SpreadSheetの「拡張機能」から「Apps Script」を選択して作成しましょう。

対象サイトのURLを取得

対象サイトのURLを取得するための関数を定義します。

SHEET_IDは下記のようなURLの場合は「abcdefg」になります。

https://docs.google.com/spreadsheets/d/abcdefg/edit

const SHEET_ID = "xxx";

function getSheet(sheetName) {
  const spreadSheet = SpreadsheetApp.openById(SHEET_ID);
  // const spreadSheet = SpreadsheetApp.getActiveSpreadsheet();  これでもOK!(SHEET_IDが不要)
  return spreadSheet.getSheetByName(sheetName);
}

function getFeedUrls() {
  const sheet = getSheet("feeds");
  // シートの全てのデータを取得
  const values = sheet.getDataRange().getValues();
  const feedUrls = values.map((value, index) => {
    // ヘッダー部分を除く
    if (index === 0) return null;
    return value[1];
  });
  // nullを除くためのfilter(Boolean);
  return feedUrls.filter(Boolean);
}

モグモグさん

getFeedUrlsで対象サイトのURLの配列を取得することができるようになりました。

既に取得したデータの重複を防ぐための関数を定義

取得したデータはnewsというタブ(シート)に表示するようにしていくのですが、すでに取得したデータはSpreadSheetに追記したくないので、getSavedUrlsという関数を定義しました。

この関数は、取得したデータのURL一覧を返す関数です。

モグモグさん

この後使います!

function getSavedUrls() {
  const sheet = getSheet("news");
  const values = sheet.getDataRange().getValues();
  const savedUrls = values.map((value, index) => {
    // ヘッダー部分を除く
    if (index === 0) return null;
    return value[1];
  });
  // nullを除くためのfilter(Boolean);
  return savedUrls.filter(Boolean);
}

データを取得する関数を定義

続いて、データを取得する関数を実装します。

対象サイトをループしてデータを取得し、データをさらにループして最終的に2次元配列(例:[["title1", "https://xxx"], [["title2", "https://xxx"]])を返しています。

モグモグさん

ループの中でSpreadSheetに書き込んでも問題ないですが、リクエスト回数を減らすために2次元配列を返してこの後の手順で一気に書き込みます。

日付をフォーマットしたり、ソートを入れていますがこちらは皆さんのお好きなように変更してください!

function getRssData() {
  // 対象サイトのURLを取得
  const feedUrls = getFeedUrls();
  // 既に取得しているデータのURLを取得
  const savedUrls = getSavedUrls();
  const dataList = [];
  feedUrls.forEach((url) => {
    const xml = UrlFetchApp.fetch(url).getContentText();
    const document = XmlService.parse(xml);
    const root = document.getRootElement();
    const channel = root.getChild('channel');
    const items = channel.getChildren('item');

    items.forEach((item) => {
      const link = item.getChild('link').getText();
      // 重複がなければ処理
      if (!savedUrls.some((savedUrl) => savedUrl === link)) {
        const itemList = []
        itemList.push(item.getChild('title').getText()); // title
        itemList.push(link); // link
        itemList.push(Utilities.formatDate(new Date(item.getChild('pubDate').getValue()), "JST", "yyyy-MM-dd HH:mm")); // date
        dataList.push(itemList);
      };
    });
    Utilities.sleep(2000);
  });
  // 古い順にソート
  dataList.sort((a, b) => a[2] > b[2] ? 1 : -1);
  return dataList;
}

補足

RSS1.0やATOMに対応する場合は、データ取得部分のコードを変更する必要があります。

SpreadSheetにデータを書き込む

最後にSpreadSheetにデータを書き込んでいきます

最終行を取得して、取得したデータを追記していけるようになっています。

モグモグさん

こちらがメインの関数です!

function saveRssData() {
  const sheet = getSheet("news");
  const data = getRssData();
  // データが1つでもあればSpreadSheetに書き込む
  if (data.length >= 1) {
    const lastRow = sheet.getDataRange().getLastRow();
    // A:最終行+1にデータの長さとカラム数(タイトル/URL/日付)の範囲に書き込む
    sheet.getRange(lastRow + 1, 1, data.length, 3).setValues(data);
  };
}

実行結果

GASでsaveRssDataを実行すると、newsタブ(シート)にこのように書き込まれます。

新しいデータが取得できると重複なく最終行の次に書き込まれます!

全体のコード

これでデータを取得してSpreadSheetに書き込むことができました

全体のコードを載せておきます!

const SHEET_ID = "xxx";

function getSheet(sheetName) {
  const spreadSheet = SpreadsheetApp.openById(SHEET_ID);
  return spreadSheet.getSheetByName(sheetName);
}

function getFeedUrls() {
  const sheet = getSheet("feeds");
  const values = sheet.getDataRange().getValues();
  const feedUrls = values.map((value, index) => {
    // ヘッダー部分を除く
    if (index === 0) return null;
    return value[1];
  });
  // nullを除くためのfilter(Boolean);
  return feedUrls.filter(Boolean);
}

function getSavedUrls() {
  const sheet = getSheet("news");
  const values = sheet.getDataRange().getValues();
  const savedUrls = values.map((value, index) => {
    // ヘッダー部分を除く
    if (index === 0) return null;
    return value[1];
  });
  // nullを除くためのfilter(Boolean);
  return savedUrls.filter(Boolean);
}

function getRssData() {
  // 対象サイトのURLを取得
  const feedUrls = getFeedUrls();
  // 既に取得しているデータのURLを取得
  const savedUrls = getSavedUrls();
  const dataList = [];
  feedUrls.forEach((url) => {
    const xml = UrlFetchApp.fetch(url).getContentText();
    const document = XmlService.parse(xml);
    const root = document.getRootElement();
    const channel = root.getChild('channel');
    const items = channel.getChildren('item');

    items.forEach((item) => {
      const link = item.getChild('link').getText();
      // 重複がなければ処理
      if (!savedUrls.some((savedUrl) => savedUrl === link)) {
        const itemList = []
        itemList.push(item.getChild('title').getText()); // title
        itemList.push(link); // link
        itemList.push(Utilities.formatDate(new Date(item.getChild('pubDate').getValue()), "JST", "yyyy-MM-dd HH:mm")); // date
        dataList.push(itemList);
      };
    });
    Utilities.sleep(2000);
  });
  // 古い順にソート
  dataList.sort((a, b) => a[2] > b[2] ? 1 : -1);
  return dataList;
}

function saveRssData() {
  const sheet = getSheet("news");
  const data = getRssData();
  // データが1つでもあればSpreadSheetに書き込む
  if (data.length >= 1) {
    const lastRow = sheet.getDataRange().getLastRow();
    // A:最終行+1にデータの長さとカラム数(タイトル/URL/日付)の範囲に書き込む
    sheet.getRange(lastRow + 1, 1, data.length, 3).setValues(data);
  };
}

定期実行のためにトリガーの設定

データを取得して書き込む処理が完成したので、トリガーを設定して定期実行できるようにしていきます

トリガーの設定

トリガーの設定

オンラインエディター画面からトリガーを選択します。

「トリガーを追加」から実行関数をsaveRssDataにします。

トリガーのタイプを時間手動型にして任意の間隔を設定してください!

まとめ

Google Apps Script(GAS)でRSSリーダーを作成する方法を解説しました。

重複データを考慮し新しいデータを定期実行で取得し書き込むという実用的なものができたのではないかと思います。

情報収集や会社内での活用など有益な使い道になれば幸いです。