TL;DR (この記事でできること)
この記事を読むことで、n8n, Google Apps Script (GAS), Googleスプレッドシートを連携させ、任意のキーワードの検索トレンドを定点観測し、変動があった際にSlackへ自動通知するパイプラインを構築できます。
- 監視したいキーワードをスプレッドシートにリストアップするだけで、
- 毎日自動でトレンドデータを取得・蓄積し、
- 前週比で急上昇したキーワードを検知してSlackにアラートを飛ばす
という一連の流れを、ノーコードとローコードの組み合わせで実現します。
はじめに
こんにちは!Qiitaでは主にAPI連携や業務自動化に関する記事を投稿している @YushiYamamoto です。
先日、Googleから公式のGoogle Trends API(アルファ版)が発表され、界隈では大きな話題となりました。これまで非公式な方法でしかアクセスできなかったトレンドデータに、ついに公式の道が開かれようとしています。
しかし、アルファ版はまだ一部のテスターにしか公開されておらず、我々が自由に利用できるのはもう少し先になりそうです。そこで本記事では、公式APIの登場を見据えつつ、今すぐ使えるサードパーティAPI(SerpApi)を利用して、トレンドデータの自動分析パイプラインを構築する手順を具体的に解説します。
迅速なプロトタイピングが得意なノーコードツールn8nと、Googleサービスとの連携に優れ柔軟な処理が可能なGASを組み合わせることで、効率的かつ拡張性の高い仕組みを目指します。
システム全体構成図
今回構築するシステムのアーキテクチャは以下の通りです。データがどのように流れ、処理されていくのかを把握しておきましょう。
- n8n: 定期実行、キーワード読み込み、APIリクエスト、データ加工、GASへのデータ連携を担当します。
- GAS: n8nからのデータを受け取り、スプレッドシートへの記録、閾値判定、Slackへの通知を行います。
前提環境・準備するもの
本記事の手順を再現するために、以下のツールやアカウントを準備してください。
- n8nアカウント: n8n Cloud またはセルフホスト環境 (v1.x で動作確認)
-
Googleアカウント:
- Googleスプレッドシート
- Google Apps Script
- Google Cloud Platform プロジェクト (特に設定は不要ですが、GASが利用するプロジェクトとして存在している必要があります)
-
SerpApiアカウント:
- Google Trends APIへのプロキシとして利用します。
- 無料プラン(100 Searches/month)で動作確認が可能です。
- アカウント登録後、API Key を取得しておきます。
-
Slackワークスペース:
- 通知を受け取るためのチャンネル。
- Incoming Webhookアプリをチャンネルに追加し、Webhook URLを取得しておきます。
実装手順
1. Googleスプレッドシートの準備
まず、キーワードリストとデータログを格納するスプレッドシートを作成します。
- 新しいスプレッドシートを作成し、名前を「Google Trends Tracker」などとします。
- シートを2つ作成します。
-
Keywordsシート: 監視したいキーワードをA列に入力します。A keyword n8n GAS ChatGPT -
Logシート: n8nから取得したデータを記録します。ヘッダー行を1行目に作成しておきます。A B C D timestamp keyword latest_value weekly_change
-
2. Google Apps Script (GAS) の実装
次に、n8nからのデータを受け取り、スプレッドシートへの記録とSlack通知を行うGASを実装します。
- 先ほど作成したスプレッドシートのメニューから
拡張機能>Apps Scriptを開きます。 - 以下のコードをコピー&ペーストし、
コード.gsの内容を置き換えます。 -
YOUR_SLACK_WEBHOOK_URLとYOUR_SPREADSHEET_IDを自身のものに書き換えてください。(スプレッドシートIDはURLの.../d/と/editの間の文字列です) -
重要: スクリプトプロパティにSlackのWebhook URLを設定します。
- スクリプトエディタの左側メニューから「プロジェクトの設定」(歯車アイコン)をクリックします。
- 「スクリプト プロパティ」セクションで「スクリプト プロパティを追加」をクリックし、以下の通り設定します。
-
プロパティ:
SLACK_WEBHOOK_URL - 値: あなたのSlack Incoming Webhook URL
-
プロパティ:
- スクリプトを保存します。
// doPost(e): n8nからのPOSTリクエストを受け取るメイン関数
function doPost(e) {
try {
// スクリプトプロパティからWebhook URLを取得
const props = PropertiesService.getScriptProperties();
const SLACK_WEBHOOK_URL = props.getProperty('SLACK_WEBHOOK_URL');
if (!SLACK_WEBHOOK_URL) {
throw new Error('SlackのWebhook URLがスクリプトプロパティに設定されていません。');
}
// POSTされたJSONデータをパース
const postData = JSON.parse(e.postData.contents);
const keyword = postData.keyword;
const latestValue = postData.latest_value;
const previousValue = postData.previous_value;
// 前週比の変化率を計算 (0除算を避ける)
const weeklyChange = previousValue !== 0
? ((latestValue - previousValue) / previousValue) * 100
: (latestValue > 0 ? 100 : 0);
// ログシートにデータを記録
const logSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Log');
const timestamp = new Date();
logSheet.appendRow([timestamp, keyword, latestValue, weeklyChange.toFixed(2)]);
// 閾値(例: 前週比20%以上の上昇)を超えたらSlackに通知
const THRESHOLD = 20.0;
if (weeklyChange >= THRESHOLD) {
const message = `📈 トレンド急上昇アラート\nキーワード: *${keyword}*\nトレンドスコア: ${latestValue} (+${weeklyChange.toFixed(1)}% vs 前週)`;
sendToSlack(SLACK_WEBHOOK_URL, message);
}
// 成功レスポンスを返す
return ContentService.createTextOutput(JSON.stringify({ status: 'success', keyword: keyword })).setMimeType(ContentService.MimeType.JSON);
} catch (error) {
// エラーハンドリング
console.error(error);
sendToSlack(SLACK_WEBHOOK_URL, `GASスクリプトでエラーが発生しました: ${error.message}`);
return ContentService.createTextOutput(JSON.stringify({ status: 'error', message: error.message })).setMimeType(ContentService.MimeType.JSON);
}
}
// sendToSlack(url, message): Slackにメッセージを送信するヘルパー関数
function sendToSlack(url, message) {
const payload = {
text: message,
};
const options = {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(payload),
};
UrlFetchApp.fetch(url, options);
}
- スクリプトをウェブアプリとしてデプロイします。
- 右上の
デプロイ>新しいデプロイをクリック。 -
種類の選択でウェブアプリを選択。 -
アクセスできるユーザーを全員に設定します。(重要:自分のみだとn8nからアクセスできません) -
デプロイをクリックし、表示される ウェブアプリのURL をコピーしておきます。これがn8nから叩くWebhook URLになります。
- 右上の
3. n8n ワークフローの構築
最後に、n8nで一連の処理を行うワークフローを作成します。
Node 1: Schedule Trigger
- 定期実行のトリガーです。
-
Trigger Interval:
Every Day -
Hour:
8(お好みの時間でOK)
Node 2: Google Sheets (Read)
-
Keywordsシートから監視対象のキーワードを読み込みます。 - Credential: 自身のGoogleアカウントを接続します。
-
Operation:
Read - Spreadsheet ID: 準備したスプレッドシートのIDを指定。
-
Sheet Name:
Keywords -
Range:
A2:A(ヘッダー行をスキップ)
Node 3: HTTP Request (SerpApi)
- 各キーワードのトレンドデータをSerpApi経由で取得します。
-
Credential for Authentication:
Header Authを選択し、新しいCredentialを作成します。-
Name:
SerpApi -
Header Name:
api_key(SerpApiの仕様ではパラメータですが、ここでは便宜上こうします。実際にはURLパラメータで渡します) - Header Value: あなたのSerpApiのAPIキー
-
Name:
-
URL:
https://serpapi.com/search -
Options > Query Parameters:
-
Name:
engine, Value:google_trends -
Name:
q, Value (Expression):{{ $json.keyword }} -
Name:
data_type, Value:TIMESERIES -
Name:
api_key, Value (Expression):{{ $credentials.SerpApi.apiKey }}
-
Name:
(スクリーンショットのイメージ)
Node 4: Function
- SerpApiのレスポンス(複雑なJSON)から必要なデータ(直近と1週間前のトレンドスコア)を抽出・加工します。
- 以下のJavaScriptコードを貼り付けます。
// SerpApiのレスポンスから最新と1週間前のデータを抽出
const items = $input.all();
const results = [];
for (const item of items) {
const timelineData = item.json.interest_over_time.timeline_data;
// データが2つ以上ないと比較できないのでスキップ
if (timelineData.length < 2) {
continue;
}
// 最新のデータ(配列の最後)
const latestData = timelineData[timelineData.length - 1];
// 1週間前のデータ(配列の最後から8番目、日次データなので)
// データが足りない場合も考慮
const previousData = timelineData.length >= 8
? timelineData[timelineData.length - 8]
: timelineData[0];
const newItem = {
json: {
keyword: item.json.search_parameters.q,
latest_value: latestData.values[0].extracted_value,
previous_value: previousData.values[0].extracted_value,
}
};
results.push(newItem);
}
return results;
Node 5: HTTP Request (Call GAS)
- 加工したデータをGASのWebhook URLにPOSTします。
- URL: GASデプロイ時にコピーしたウェブアプリのURL
-
Method:
POST -
Body Content Type:
JSON -
Body (Expression):
{{ $json }}
これでワークフローは完成です!Execute Workflowでテスト実行し、Logシートにデータが書き込まれ、閾値を超えた場合にSlackに通知が届けば成功です。
ハマりどころと解決策 (Gotchas!)
この仕組みを構築・運用する上で、私が実際にハマったポイントや注意点を共有します。
1. APIのレート制限とコスト
- SerpApi無料枠: 無料プランは月100リクエストまでです。キーワードが10個あれば10日で上限に達します。本格運用するなら有料プラン($50/month〜)への移行が必要です。
-
公式APIの場合: まだ詳細は不明ですが、Google CloudのAPIと同様にQuotaが設定されるはずです。大量のキーワードを短時間にリクエストすると
429 Too Many Requestsエラーが発生する可能性が高いため、n8nのWaitノードをループ内に挟み、リクエスト間隔を調整する設計が有効です。
2. GASの実行時間制限(6分の壁)
- キーワード数が数十〜数百個になると、n8nのループ処理全体で6分を超え、GAS側がタイムアウトする可能性があります。
-
対策: n8nの
SplitInBatchesノードを使い、キーワードリストを例えば50個ずつのバッチに分割します。そして、バッチごとにGASを呼び出すことで、1回あたりの処理時間を短縮し、制限を回避できます。
3. n8nのExpressionの罠(JSONの深い階層)
- SerpApiのレスポンスJSONは階層が深いため、Expressionでデータを指定するのが少し厄介です。
-
例:
{{ $json.interest_over_time.timeline_data[0].values[0].extracted_value }} -
解決策: n8nのExpression Editorはオートコンプリートが非常に優秀です。
$json.と入力した後にinterest_over_timeを選択し、ドットで繋いでいくと目的のデータにたどり着きやすくなります。また、HTTP Requestノードの実行結果を右ペインで確認しながらパスを組み立てるのが確実です。
4. 認証情報(Credentials)のハードコーディングは避ける
- APIキーやWebhook URLをワークフロー内に直接書き込むと、ワークフローをエクスポート・共有した際にキーが漏洩するリスクがあります。
-
対策: 必ずn8nの
Credentials機能を使って認証情報を管理しましょう。これにより、ワークフローのロジックと機密情報が分離され、安全に運用できます。{{ $credentials.YourCredentialName.property }}の形式で呼び出せます。
5. GASのデプロイ更新忘れ
- GASのコードを修正した後、
デプロイ>デプロイを管理> (対象のデプロイを選択) >編集(鉛筆アイコン) >新しいバージョンを選択してデプロイしないと、変更がウェブアプリに反映されません。ただ保存しただけではダメ、というのは初心者がよくハマる罠です。
応用・発展
この基本的な仕組みを拡張するためのアイデアをいくつか紹介します。
-
BigQueryへのデータ蓄積と可視化:
GASからスプレッドシートだけでなく、BigQueryにもデータをインサートするように変更します。これにより、数百万行規模のデータを高速に集計・分析し、Looker Studioなどで高度なダッシュボードを構築できます。 -
異常検知ロジックの高度化:
単純な前週比だけでなく、移動平均線からの乖離率や標準偏差(3σ法)を用いた統計的な異常検知をGASやn8nのFunctionノードで実装することで、ノイズに強いアラートシステムを構築できます。 -
GA4データとの相関分析:
Google Analytics Data APIを使い、特定ページのPV数やコンバージョン数を取得。検索トレンドの変動と実際のサイトパフォーマンスの相関を分析することで、「トレンド上昇がビジネスインパクトに繋がったか」を定量的に評価できます。
まとめ
本記事では、n8nとGASを連携させ、Google Trendsのデータを自動で収集・分析・通知するパイプラインの構築手順を解説しました。
公式APIの一般公開はまだ先ですが、今回のようなサードパーティAPIを利用することで、その価値を先取りして体験し、来るべき日のために知見を溜めておくことができます。
ノーコードツールで素早く全体を組み上げ、複雑なロジックや外部連携が必要な部分だけをGAS(コード)で補うハイブリッドなアプローチは、多くの自動化プロジェクトで有効な手法です。ぜひ、あなたの業務効率化にも役立ててみてください。
最後までお読みいただきありがとうございました!この記事が役に立ったと思ったら、ぜひLGTMをお願いします!