見出し画像

【GASコード記載】Googleニュース・Zenn・note × Discord スクレイピングシステムの作り方

はじめに

本記事では、Googleニュース・Zenn・noteのDify関連記事を自動取得し、Discordに投稿するシステム の作り方を解説します。

完成イメージ

discordにてあなたの興味関心に絞ったニュースが毎日届く、という自動的な仕組みを簡単に構築することができます。
こちらの仕組みではZennとnoteのスクレイピングにあたりGoogle Serp APIを使用していますが、毎月の無料クレジットで収めることも可能です。

Googleニュース取得
note記事取得


以下のような機能を実装します。

  • Googleニュースの最新Dify記事を取得

  • ZennのDify関連記事を取得(SerpAPI使用)

  • NoteのDify関連記事を取得(SerpAPI使用)

  • 取得した記事をDiscordに自動投稿

  • GAS(Google Apps Script)で定期実行(トリガー設定)

必要な準備

1️⃣ Google Apps Script(GAS)の基本設定

  1. Google Apps Script にアクセス

  2. 新しいプロジェクトを作成

  3. スクリプトプロパティを設定する

    • SERPAPI_KEY:SerpAPIのAPIキー

    • DISCORD_WEBHOOK_URL:DiscordのWebhook URL

2️⃣ Discord Webhookの作成

  1. Discordで投稿したいチャンネルを開く

  2. 「編集」→「アプリの統合」→「Webhookを作成」

  3. WebhookのURLを取得し、スクリプトプロパティに保存

3️⃣ SerpAPIの登録 & APIキー取得

  1. SerpAPI にアクセスし、新規登録

  2. ダッシュボードでAPIキーを取得

  3. スクリプトプロパティに保存(SERPAPI_KEY)

4️⃣ GoogleニュースのRSSを取得する方法

GoogleニュースではRSSフィードを利用可能です。

  • Dify関連記事のRSSフィード

    • https://news.google.com/rss/search?q=Dify+AI&hl=ja&gl=JP&ceid=JP:ja

GASの実装

🔧 キーワードを変更する方法

このシステムは「Dify」に関する記事を取得するように設定されていますが、別のキーワードを調べたい場合は以下の箇所を変更するだけです!

🔹 Googleニュースの検索キーワードを変更

  • fetchGoogleNews() の NEWS_URL を編集すれば、Googleニュースの検索対象を変更できます。

const NEWS_URL = "https://news.google.com/rss/search?q=あなたのキーワード&hl=ja&gl=JP&ceid=JP:ja";

例えば、「AIニュース」を取得したい場合は:

const NEWS_URL = "https://news.google.com/rss/search?q=AI&hl=ja&gl=JP&ceid=JP:ja";

🔹 Zenn & note の検索キーワードを変更

  • searchDifyArticles("site:zenn.dev Dify") の Dify を変更すれば、Zennとnoteの検索キーワードを変更できます。

const zennArticles = searchDifyArticles("site:zenn.dev あなたのキーワード");
const noteArticles = searchDifyArticles("site:note.com あなたのキーワード");

例えば、「ChatGPT」についての記事を取得したい場合:

const zennArticles = searchDifyArticles("site:zenn.dev ChatGPT");
const noteArticles = searchDifyArticles("site:note.com ChatGPT");

これで、Dify以外のトピックでも自動取得・Discord通知が可能になります! 

🎯 これを貼り付ければOK!

以下のコードをGoogle Apps Scriptに貼り付ければ、そのまま動作します。
※内容はDifyのニュースに関してのスクレイピングです

const SERPAPI_URL = "https://serpapi.com/search";

function getScriptProperty(key) {
  return PropertiesService.getScriptProperties().getProperty(key);
}

function fetchGoogleNews() {
  const NEWS_URL = "https://news.google.com/rss/search?q=Dify+AI&hl=ja&gl=JP&ceid=JP:ja";
  const response = UrlFetchApp.fetch(NEWS_URL);
  const xml = response.getContentText();
  return parseRSS(xml);
}

function parseRSS(xml) {
  const doc = XmlService.parse(xml);
  const root = doc.getRootElement();
  const channel = root.getChild("channel");
  const items = channel.getChildren("item");
  return items.slice(0, 3).map(item => ({
    title: item.getChildText("title"),
    url: item.getChildText("link")
  }));
}

function searchDifyArticles(query) {
  const apiKey = getScriptProperty("SERPAPI_KEY");
  if (!apiKey) return [];

  const url = `${SERPAPI_URL}?engine=google&q=${encodeURIComponent(query)}&api_key=${apiKey}`;
  const response = UrlFetchApp.fetch(url);
  const json = JSON.parse(response.getContentText());
  
  return json.organic_results ? json.organic_results.slice(0, 3).map(item => ({ title: item.title, url: item.link })) : [];
}

function postToDiscord(articles) {
  const webhookUrl = getScriptProperty("DISCORD_WEBHOOK_URL");
  if (!webhookUrl) return;

  const content = articles.map(article => `📝 **${article.title}**
🔗 ${article.url}`).join("

");
  const payload = JSON.stringify({ content });

  UrlFetchApp.fetch(webhookUrl, {
    method: "post",
    contentType: "application/json",
    payload: payload
  });
}

function main() {
  const googleNews = fetchGoogleNews();
  const zennArticles = searchDifyArticles("site:zenn.dev Dify");
  const noteArticles = searchDifyArticles("site:note.com Dify");
  
  const allArticles = [...googleNews, ...zennArticles, ...noteArticles];
  if (allArticles.length > 0) {
    postToDiscord(allArticles);
  } else {
    Logger.log("取得できる記事がありませんでした。");
  }
}

📌 Googleニュースのスクレイピング(RSS取得)

function fetchGoogleNews() {
  const NEWS_URL = "https://news.google.com/rss/search?q=Dify+AI&hl=ja&gl=JP&ceid=JP:ja";
  const response = UrlFetchApp.fetch(NEWS_URL);
  const xml = response.getContentText();
  return parseRSS(xml);
}

function parseRSS(xml) {
  const doc = XmlService.parse(xml);
  const root = doc.getRootElement();
  const channel = root.getChild("channel");
  const items = channel.getChildren("item");
  return items.slice(0, 3).map(item => ({
    title: item.getChildText("title"),
    url: item.getChildText("link")
  }));
}

📌 Zenn & Noteの記事取得(SerpAPI利用)

const SERPAPI_URL = "https://serpapi.com/search";

function searchDifyArticles(query) {
  const apiKey = PropertiesService.getScriptProperties().getProperty("SERPAPI_KEY");
  if (!apiKey) return [];

  const url = `${SERPAPI_URL}?engine=google&q=${encodeURIComponent(query)}&api_key=${apiKey}`;
  const response = UrlFetchApp.fetch(url);
  const json = JSON.parse(response.getContentText());
  
  return json.organic_results ? json.organic_results.slice(0, 3).map(item => ({ title: item.title, url: item.link })) : [];
}

📌 Discordに投稿する処理

function postToDiscord(articles) {
  const webhookUrl = PropertiesService.getScriptProperties().getProperty("DISCORD_WEBHOOK_URL");
  if (!webhookUrl) return;

  const content = articles.map(article => `📝 **${article.title}**\n🔗 ${article.url}`).join("\n\n");
  const payload = JSON.stringify({ content });

  UrlFetchApp.fetch(webhookUrl, {
    method: "post",
    contentType: "application/json",
    payload: payload
  });
}

📌 メイン関数

function main() {
  const googleNews = fetchGoogleNews();
  const zennArticles = searchDifyArticles("site:zenn.dev Dify");
  const noteArticles = searchDifyArticles("site:note.com Dify");
  
  const allArticles = [...googleNews, ...zennArticles, ...noteArticles];
  if (allArticles.length > 0) {
    postToDiscord(allArticles);
  } else {
    Logger.log("取得できる記事がありませんでした。");
  }
}

GASのトリガー設定

  1. GASのエディタを開く

  2. 左の時計アイコン(トリガー)をクリック

  3. 新しいトリガーを作成し、毎日実行に設定

まとめ

このシステムを使えば、Difyに関する最新ニュースをGoogleニュース・Zenn・noteから取得し、Discordに自動投稿できます!

もしカスタマイズしたい場合は、取得するキーワードを変更することで、他のトピックにも対応可能です!

📢

いいなと思ったら応援しよう!