Googleスプレッドシート、GSC、ChatGPT API を使用して SEO分析を自動化する方法

公開日:2025/02/06

最終更新日:2025/02/14

ブログ

無料で資料をダウンロード

SEOサービスのご案内
専門のコンサルタントが貴社サイトのご要望・課題整理から施策の立案を行い、検索エンジンからの流入数向上を支援いたします。

無料ダウンロードする >>

この記事は、2025年1月30日に Search Engine Land で公開された  Ludwig Makhyan氏「Automate SEO analysis with Google Sheets, GSC & ChatGPT API」を翻訳したものです。

Google スプレッドシートを使えば、サイト監査の自動化、ページ分析、AIを活用した最適化のためのインサイト生成を一括で行うことができます。

SEO分析は多くの時間を要しますが、自動化を取り入れることで反復作業を減らし、重要なWebサイトの最適化を迅速に行えるようになります。

本ガイドでは、Googleスプレッドシート、Google Search Console(GSC)、ChatGPT APIを活用して、カスタムツールを構築し、SEO監査を効率化する方法を詳しく解説します。これにより、AIを活用した最適化のためのインサイト生成を一括で行うことができます。

このツールでできること

  • GSCデータの取得を自動化し、分析のスピードを向上させる
  • AIを活用して、実用的なSEOの改善提案を生成する

仕組み

まず、GSCに接続されているドメインからURLを選択し、ChatGPT APIキーを入力。その後、ページを分析し、AIを活用したSEOインサイトを取得します。すべての作業はGoogleスプレッドシート上で完結します。

自動化できるSEO分析とは?

このツールを設定すると、キーワードランキング、参照 URL、最終クロール日、robots.txt のインデックス作成ステータスなど、GSC からの主要な SEO データにすばやくアクセスできるようになります。

さらに、ChatGPTを活用することで、以下の項目を分析し、改善のための推奨事項を提供します。

  • タイトルタグ
  • メタディスクリプション
  • 見出しタグ
  • コンテンツの最適化
  • キーワードの配置
  • 内部リンクの構造
  • モバイル最適化
  • ローカルSEO対策
  • スキーママークアップ

このスクリプトはすべてを網羅できるわけではありませんが、数秒で詳細なページ分析情報を提供し、手作業にかかる時間を大幅に削減できます。
分析結果を確認した上で、どの推奨事項を実施するかを決定できます。

独自のGSCカスタムツール+スクリプトを設定する8つの手順

スクリプトの設定は一見複雑に思えるかもしれませんが、各手順を慎重に実行し、スクリプトをコピーして適切に動作することを確認すれば、スムーズに導入できます。

事前に準備するものは以下です。

  • ChatGPT APIキー
  • Google スプレッドシート
  • Google Search Console(リンクされたプロパティを含む)
  • Google Cloud Consoleのデータプロジェクト

それでは、このツールを稼働させるための8つのステップを順番に説明していきます。

ステップ1:ツール用のGoogleスプレッドシートを作成する

Googleアカウントをお持ちであれば、以下の手順で簡単に作成できます。

  1. Google ドライブを開く
  2. ツールを保存するフォルダーへ移動
  3. 画面の背景を右クリック
  4. [Google スプレッドシート] → [空白のスプレッドシート] を選択

シート名は自由に設定できますが、今回は「GSC カスタム ツール」と名付けました。

ステップ2:シートに入力する

D1 に ChatGPT API キーを貼り付けます。このキーがない場合は、上記のリンクにアクセスして、このツールが機能するために必要なキーを取得してください。

ここで、両方の列のいくつかの行を結合する必要があります。次の手順に従って、F2 ~ F30 と G2 ~ G30 を個別に結合します。

  • 結合する行を選択します。
  • [書式] > [セルの結合] > [垂直方向に結合]に移動します。

結合する必要がある F 行と G 行に対してこの手順を繰り返します。

ステップ3: Google Cloudプロジェクトを作成する

ツール用の Google Cloud Console データ プロジェクトを作成します。

セットアップが完了したら、「GSC Custom Tool」という名前の新しいプロジェクトを作成します。

Select Project > New Project に移動し、スクリーンショットの例と同様に情報を入力します。

プロジェクトの名前を設定したら、Create をクリックします。

次に、Google Search Console API をプロジェクトに接続します。

検索バーに「Google Search Console API」と入力して選択し、次の画面で「有効にする」をクリックします。

まだやるべきことはたくさんありますが、近いうちにこのプロジェクトを再検討する予定です。

さらに詳しく: SEO タスクを自動化する 5 つの Python スクリプト

ステップ4: アクセスライセンス情報を追加する

さらに調整するには、Google Cloud Console に戻ります。 

画面の左側にある「Credentials」をクリックします。

画面上部の「+CREATE CREDENTIALS」をクリックし、 OAuth Client ID を選択します。 

「Configure Consent Screen」に移動し、「External」を選択します。画面を作成し、以下の情報を入力します。

  • アプリ名
  • GSC アカウントにリンクされたサポートメール
  • 開発者の連絡先情報

入力後、「Save and continue」をクリックし、次の画面(「Add or Remove Scopes」)に進みます。

「Google Search Console API」のスコープを選択し、更新します。その後、「Save and continue」をクリックします。

アクセス権を付与したいユーザーを追加し、「Save and continue」をクリックします。

ステップ 5: GSC データ用の Google Cloud プロジェクトに変更する

ハンバーガーアイコンをクリックし、Cloud overview > Dashboard に移動します。

ページに表示されている プロジェクト番号 をコピーします。

プロジェクト番号に移動し、それを選択して CTRL + C でコピーします。

Google スプレッドシートのファイルを開き、Project Settings と書かれた歯車アイコンをクリックします。

テキストボックスにプロジェクト番号を貼り付け、Set project をクリックします。

ステップ6: Google Apps Scriptに名前を付ける

スクリプトの管理をしやすくするために、名前を追加します。

これを行うには、Project History に移動し、画面上部にある Untitled project をクリックします。

「GSC Custom Tool」と入力して、プロジェクト名を設定します。

ステップ7: マニフェストファイルを編集する

新しく作成した Google スプレッドシート ファイルに Apps Script を統合します。

これを行うには、ファイルを開き、Extensions > Apps Script に移動します。

次に、以下のコードをコピー&ペーストします。

(コードウィンドウ内のコードを選択し、CTRL + C を押してコピーします。その後、Apps Script に戻り、CTRL + V を押してコードを貼り付けます。)

{
  “timeZone”: “America/New_York”,
  “dependencies”: {},
  “exceptionLogging”: “STACKDRIVER”,
  “oauthScopes”: [
    “https://www.googleapis.com/auth/webmasters”,
    “https://www.googleapis.com/auth/webmasters.readonly”,
    “https://www.googleapis.com/auth/script.external_request”,
    “https://www.googleapis.com/auth/spreadsheets”,
    “https://www.googleapis.com/auth/spreadsheets.currentonly”
  ],
  “runtimeVersion”: “V8”
}

ステップ8: アプリスクリプトを作成する

すべてを貼り付けたら、Code.js ファイルに移動して次のコードを貼り付けます。

// Store the OAuth token and logs in script properties
const scriptProperties = PropertiesService.getScriptProperties();
const OPENAI_URL = “https://api.openai.com/v1/chat/completions”;
const SYSTEM_MESSAGE = { role: “system”, content: “You are a helpful SEO expert.” };


function log(message) {
  Logger.log(message); // Regular Apps Script logging
  const logs = scriptProperties.getProperty(‘customLogs’) || ”;
  scriptProperties.setProperty(‘customLogs’, logs + ‘\n’ + message); // Append message to logs
}


function resetLogs() {
  scriptProperties.deleteProperty(‘customLogs’); // Clear logs for a new execution
}


function getLogs() {
  return scriptProperties.getProperty(‘customLogs’) || ‘No logs available.’;
}


function fetchOAuthToken() {
  let token = scriptProperties.getProperty(‘oauthToken’);
  if (!token) {
    token = ScriptApp.getOAuthToken();
    scriptProperties.setProperty(‘oauthToken’, token);
    log(‘OAuth token fetched and stored.’);
  }
  return token;
}


function onOpen() {
  const ui = SpreadsheetApp.getUi();
  ui.createMenu(‘Search Console’)
    .addItem(‘Authorize GSC’, ‘promptReauthorization’)
    .addItem(‘Fetch GSC Properties’, ‘fetchGSCProperties’)
    .addItem(‘Inspect URL’, ‘inspectUrl’) // Add the Inspect URL button
    .addItem(‘AI Analyze’, ‘aiAnalyze’) // Add the AI Analyze button
    .addToUi();
}


function promptReauthorization() {
  const ui = SpreadsheetApp.getUi();
  const response = ui.alert(
    ‘Re-authorize Script’,
    ‘Re-authorizing will revoke current permissions and require you to authorize again. Do you want to continue?’,
    ui.ButtonSet.YES_NO
  );


  if (response === ui.Button.YES) {
    try {
      scriptProperties.deleteProperty(‘oauthToken’); // Clear old token
      const token = fetchOAuthToken(); // Fetch and store new token
      log(“OAuth Token: ” + token);
      ui.alert(‘Authorization successful. No further action is required.’);
    } catch (e) {
      ui.alert(‘Authorization failed: ‘ + e.toString());
    }
  } else {
    ui.alert(‘Re-authorization canceled.’);
  }
}


function fetchGSCProperties() {
  resetLogs();
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const oauthToken = fetchOAuthToken();


  const sites = getSitesListFromGSC(oauthToken);


  if (!sites || sites.length === 0) {
    SpreadsheetApp.getUi().alert(‘No GSC properties found. Please ensure you have access to GSC properties.’);
    return;
  }


  const siteUrls = [‘Select a property’].concat(
    sites.map(site => site.siteUrl).sort()
  );


  sheet.getRange(‘A1’).setValue(‘Select GSC property’).setFontWeight(‘bold’);
  sheet.getRange(‘B1’).setDataValidation(
    SpreadsheetApp.newDataValidation()
      .requireValueInList(siteUrls, true)
      .build()
  );
  sheet.getRange(‘B1’).setValue(‘Select a property’).setFontWeight(‘bold’);
  sheet.setColumnWidth(1, 150);
  sheet.setColumnWidth(2, 350);
}


let isProcessing = false; // Global flag to prevent recursive triggering


function onEdit(e) {
  if (isProcessing) return; // Prevent re-entry during execution
  isProcessing = true; // Set flag to true


  try {
    resetLogs();
    const sheet = e.source.getActiveSheet();
    const range = e.range;


    // Always clear A3:D30 on edits to B1 or B2
    if (range.getA1Notation() === ‘B1’ || range.getA1Notation() === ‘B2’) {
      sheet.getRange(‘A3:D30’).clearContent();
      sheet.getRange(‘F1:G30’).clearContent();


      if (range.getA1Notation() === ‘B1’) {
        const selectedProperty = range.getValue();


        // Clear A2 and set loading state
        sheet.getRange(‘A2’).setValue(‘Loading results…’).setFontWeight(‘bold’);
        sheet.getRange(‘B2’).clearContent();


        if (selectedProperty === ‘Select a property’) {
          sheet.getRange(‘A2’).clearContent();
          sheet.getRange(‘B2’).clearContent();
          return;
        }


        const oauthToken = fetchOAuthToken();
        const urls = getUrlsForProperty(selectedProperty, oauthToken);


        if (!urls || urls.length === 0) {
          sheet.getRange(‘A2’).setValue(‘No URLs found’).setFontWeight(‘bold’);
          sheet.getRange(‘B2’).clearContent();
          log(`No URLs found for property ${selectedProperty}`);
          return;
        }


        sheet.getRange(‘A2’).setValue(‘Select a URL’).setFontWeight(‘bold’);
        sheet.getRange(‘B2’).setDataValidation(
          SpreadsheetApp.newDataValidation()
            .requireValueInList([‘Select a URL’].concat(urls), true)
            .build()
        );
        sheet.getRange(‘B2’).setValue(‘Select a URL’).setFontWeight(‘bold’);
      }


      if (range.getA1Notation() === ‘B2’) {
        const selectedProperty = sheet.getRange(‘B1’).getValue();
        const selectedUrl = range.getValue();


        if (selectedUrl === ‘Select a URL’) {
          return;
        }


        sheet.getRange(‘A3’).setValue(‘Loading keywords…’).setFontWeight(‘bold’);


        const oauthToken = fetchOAuthToken();
        const keywords = getTopKeywordsForUrl(selectedProperty, selectedUrl, oauthToken);


        if (!keywords || keywords.length === 0) {
          sheet.getRange(‘A3’).setValue(‘No keywords found’).setFontWeight(‘bold’);
          log(`No keywords found for URL ${selectedUrl}`);
          return;
        }


        // Populate keywords and metrics
        sheet.getRange(‘A3:D12’).clearContent(); // Clear any loading message
        keywords.forEach((keyword, index) => {
          if (index < 10) {
            sheet.getRange(`A${3 + index}`).setValue(keyword.query).setFontWeight(‘bold’);
            sheet.getRange(`B${3 + index}`).setValue(keyword.clicks);
            sheet.getRange(`C${3 + index}`).setValue(keyword.impressions);
            sheet.getRange(`D${3 + index}`).setValue(keyword.ctr);
          }
        });
      }
    }
  } catch (error) {
    log(`Error in onEdit: ${error}`);
  } finally {
    isProcessing = false; // Reset the flag after execution
  }
}


function getApiRequestDetails(selectedProperty) {
  const payload = {
    startDate: getThreeMonthsAgo(),
    endDate: getToday(),
    dimensions: [“page”],
    rowLimit: 100,
    orderBy: [{ fieldName: “clicks”, sortOrder: “DESCENDING” }]
  };


  const apiUrl = `https://www.googleapis.com/webmasters/v3/sites/${encodeURIComponent(selectedProperty)}/searchAnalytics/query`;
  return { url: apiUrl, payload: payload };
}


function getSitesListFromGSC(oauthToken) {
  try {
    const url = ‘https://www.googleapis.com/webmasters/v3/sites’;


    const headers = {
      ‘Authorization’: ‘Bearer ‘ + oauthToken,
      ‘Content-Type’: ‘application/json’
    };


    const options = {
      method: ‘get’,
      headers: headers,
      muteHttpExceptions: true
    };


    const response = UrlFetchApp.fetch(url, options);
    log(`Response Code: ${response.getResponseCode()}`);
    log(`Response Content: ${response.getContentText()}`);


    if (response.getResponseCode() === 200) {
      const json = JSON.parse(response.getContentText());
      return json.siteEntry || [];
    } else {
      throw new Error(`Error fetching data: ${response.getResponseCode()} – ${response.getContentText()}`);
    }
  } catch (e) {
    log(`Error: ${e.toString()}`);
    return [];
  }
}


function getUrlsForProperty(property, oauthToken) {
  try {
    const apiUrl = `https://www.googleapis.com/webmasters/v3/sites/${encodeURIComponent(property)}/searchAnalytics/query`;


    log(`API URL: ${apiUrl}`);
    log(`OAuth Token: ${oauthToken}`);


    const payload = {
      startDate: getThreeMonthsAgo(),
      endDate: getToday(),
      dimensions: [“page”],
      rowLimit: 100,
      orderBy: [{ fieldName: “clicks”, sortOrder: “DESCENDING” }]
    };


    log(`Payload: ${JSON.stringify(payload)}`);


    const headers = {
      Authorization: `Bearer ${oauthToken}`,
      “Content-Type”: “application/json”
    };


    const options = {
      method: “post”,
      contentType: “application/json”,
      headers: headers,
      payload: JSON.stringify(payload),
      muteHttpExceptions: true
    };


    const response = UrlFetchApp.fetch(apiUrl, options);


    log(`Response Code: ${response.getResponseCode()}`);
    log(`Response: ${response.getContentText()}`);


    if (response.getResponseCode() === 200) {
      const json = JSON.parse(response.getContentText());
      return json.rows ? json.rows.map(row => row.keys[0]) : [];
    } else {
      throw new Error(`Failed to fetch data: ${response.getResponseCode()} – ${response.getContentText()}`);
    }
  } catch (e) {
    log(`Error: ${e.toString()}`);
    return [];
  }
}


function getTopKeywordsForUrl(property, url, oauthToken) {
  try {
    const apiUrl = `https://www.googleapis.com/webmasters/v3/sites/${encodeURIComponent(property)}/searchAnalytics/query`;


    log(`API URL: ${apiUrl}`);
    log(`OAuth Token: ${oauthToken}`);


    const payload = {
      startDate: getThreeMonthsAgo(),
      endDate: getToday(),
      dimensions: [“query”],
      dimensionFilterGroups: [
        {
          filters: [
            {
              dimension: “page”,
              operator: “equals”,
              expression: url
            }
          ]
        }
      ],
      rowLimit: 10,
      orderBy: [{ fieldName: “clicks”, sortOrder: “DESCENDING” }]
    };


    log(`Payload: ${JSON.stringify(payload)}`);


    const headers = {
      Authorization: `Bearer ${oauthToken}`,
      “Content-Type”: “application/json”
    };


    const options = {
      method: “post”,
      contentType: “application/json”,
      headers: headers,
      payload: JSON.stringify(payload),
      muteHttpExceptions: true
    };


    const response = UrlFetchApp.fetch(apiUrl, options);
    log(`Response Code: ${response.getResponseCode()}`);
    log(`Response: ${response.getContentText()}`);


    if (response.getResponseCode() === 200) {
      const json = JSON.parse(response.getContentText());
      return json.rows ? json.rows.map(row => ({
        query: row.keys[0],
        clicks: row.clicks,
        impressions: row.impressions,
        ctr: row.ctr
      })) : [];
    } else {
      throw new Error(`Failed to fetch data: ${response.getResponseCode()} – ${response.getContentText()}`);
    }
  } catch (e) {
    log(`Error: ${e.toString()}`);
    return [];
  }
}


function getToday() {
  const today = new Date();
  return today.toISOString().split(“T”)[0];
}


function getThreeMonthsAgo() {
  const date = new Date();
  date.setMonth(date.getMonth() – 3);
  return date.toISOString().split(“T”)[0];
}


function inspectUrl() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const url = sheet.getRange(‘B2’).getValue();
  const property = sheet.getRange(‘B1’).getValue();


  // Clear previous inspection results in A15:D30
  sheet.getRange(‘A15:D30’).clearContent();
  sheet.getRange(‘A15’).setValue(‘Inspecting…’).setFontWeight(‘bold’);


  if (!url || url === ‘Select a URL’) {
    SpreadsheetApp.getUi().alert(‘Please select a valid URL in cell B2 before inspecting.’);
    sheet.getRange(‘A15’).setValue(‘No URL selected’).setFontWeight(‘bold’);
    return;
  }


  const oauthToken = fetchOAuthToken();


  try {
    const result = callUrlInspectionApi(property, url, oauthToken);


    // Extract fields from the response
    const indexStatus = result.indexStatusResult || {};
    const mobileUsability = result.mobileUsabilityResult || {};
    const richResults = result.richResultsInfo || {};
    const referringUrls = indexStatus.referringUrls?.join(‘, ‘) || ‘None’;


    // Populate inspection results in the sheet
    sheet.getRange(‘A15’).setValue(`Inspection Results`).setFontWeight(‘bold’);
    sheet.getRange(‘A16’).setValue(`URL:`).setFontWeight(‘bold’);
    sheet.getRange(‘B16’).setValue(url);


    sheet.getRange(‘A17’).setValue(`Coverage:`).setFontWeight(‘bold’);
    sheet.getRange(‘B17’).setValue(indexStatus.coverageState || ‘Unknown’);


    sheet.getRange(‘A18’).setValue(`Robots.txt:`).setFontWeight(‘bold’);
    sheet.getRange(‘B18’).setValue(indexStatus.robotsTxtState || ‘Unknown’);


    sheet.getRange(‘A19’).setValue(`Indexing State:`).setFontWeight(‘bold’);
    sheet.getRange(‘B19’).setValue(indexStatus.indexingState || ‘Unknown’);


    sheet.getRange(‘A20’).setValue(`Last Crawled:`).setFontWeight(‘bold’);
    sheet.getRange(‘B20’).setValue(indexStatus.lastCrawlTime || ‘Not Available’);


    sheet.getRange(‘A21’).setValue(`Google Canonical:`).setFontWeight(‘bold’);
    sheet.getRange(‘B21’).setValue(indexStatus.googleCanonical || ‘Unknown’);


    sheet.getRange(‘A22’).setValue(`User Canonical:`).setFontWeight(‘bold’);
    sheet.getRange(‘B22’).setValue(indexStatus.userCanonical || ‘Unknown’);


    sheet.getRange(‘A23’).setValue(`Mobile Usability:`).setFontWeight(‘bold’);
    sheet.getRange(‘B23’).setValue(mobileUsability.verdict || ‘Unknown’);


    sheet.getRange(‘A24’).setValue(`Rich Results Eligibility:`).setFontWeight(‘bold’);
    sheet.getRange(‘B24’).setValue(richResults.verdict || ‘Unknown’);


    sheet.getRange(‘A25’).setValue(`Referring URLs:`).setFontWeight(‘bold’);
    sheet.getRange(‘B25’).setValue(referringUrls);


    // Log and alert full response for debugging
    const fullResponse = JSON.stringify(result, null, 2);
    log(`Full Inspection Result: ${fullResponse}`);
    //SpreadsheetApp.getUi().alert(`Inspection Completed. Full Response:\n\n${fullResponse}`);
  } catch (error) {
    sheet.getRange(‘A15’).setValue(‘Inspection Failed’).setFontWeight(‘bold’);
    log(`Error inspecting URL: ${error.message}`);
    SpreadsheetApp.getUi().alert(`Error inspecting URL: ${error.message}\n\nLogs:\n${getLogs()}`);
  }
}


function callUrlInspectionApi(property, url, oauthToken) {
  const apiUrl = ‘https://searchconsole.googleapis.com/v1/urlInspection/index:inspect’;


  const payload = {
    siteUrl: property,
    inspectionUrl: url,
    languageCode: ‘en-US’
  };


  const headers = {
    Authorization: `Bearer ${oauthToken}`,
    ‘Content-Type’: ‘application/json’
  };


  const options = {
    method: ‘post’,
    contentType: ‘application/json’,
    headers: headers,
    payload: JSON.stringify(payload),
    muteHttpExceptions: true
  };


  log(`API URL: ${apiUrl}`);
  log(`Payload: ${JSON.stringify(payload)}`);


  try {
    const response = UrlFetchApp.fetch(apiUrl, options);
    const responseCode = response.getResponseCode();
    const responseText = response.getContentText();


    log(`Response Code: ${responseCode}`);
    log(`Response Content: ${responseText}`);


    if (responseCode === 200) {
      const jsonResponse = JSON.parse(responseText);


      if (jsonResponse && jsonResponse.inspectionResult) {
        return jsonResponse.inspectionResult;
      } else {
        log(`Unexpected API Response Structure: ${responseText}`);
        throw new Error(‘Unexpected API response format. “inspectionResult” field is missing.’);
      }
    } else {
      log(`Failed API Call: ${responseText}`);
      throw new Error(`Failed to inspect URL. Response Code: ${responseCode}. Response: ${responseText}`);
    }
  } catch (error) {
    log(`Error during API call: ${error}`);
    throw new Error(`Error inspecting URL: ${error.message}`);
  }
}


function callChatGPT(prompt, temperature = 0.9, maxTokens = 800, model = “gpt-3.5-turbo”) {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const secretKey = sheet.getRange(‘D1’).getValue().trim(); // Retrieve the OpenAI API key from D1


  if (!secretKey) {
    throw new Error(“API Key is missing in cell D1. Please provide a valid OpenAI API key.”);
  }


  const payload = {
    model: model,
    messages: [
      SYSTEM_MESSAGE,
      { role: “user”, content: prompt }
    ],
    temperature: temperature,
    max_tokens: maxTokens
  };


  const options = {
    method: “POST”,
    headers: {
      “Content-Type”: “application/json”,
      “Authorization”: “Bearer ” + secretKey
    },
    payload: JSON.stringify(payload)
  };


  try {
    const response = UrlFetchApp.fetch(OPENAI_URL, options);
    const responseData = JSON.parse(response.getContentText());


    if (responseData.choices && responseData.choices[0] && responseData.choices[0].message) {
      return responseData.choices[0].message.content.trim();
    } else {
      log(“Unexpected response format from OpenAI: ” + JSON.stringify(responseData));
      return “Sorry, I couldn’t process the request.”;
    }
  } catch (error) {
    log(“Error calling OpenAI API: ” + error);
    return “Sorry, there was an error processing your request.”;
  }
}


function aiAnalyze() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const url = sheet.getRange(‘B2’).getValue();
  const keywords = sheet.getRange(‘A3:A12’).getValues().flat().filter(Boolean); // Get non-empty keywords
  const inspectionData = sheet.getRange(‘A16:B20’).getValues();


  // Validate input fields
  if (!url || keywords.length === 0 || inspectionData.some(row => row.length < 2 || !row[0].trim() || !row[1].trim())) {
    SpreadsheetApp.getUi().alert(“Ensure the following are filled before running AI Analyze:\n- URL in B2\n- Keywords in A3:A12\n- Inspection data in A16:B20”);
    return;
  }


  // Prepare the prompt for ChatGPT
  const prompt = `
    Analyze this URL: ${url}
    Also the view-source version from: ${url}
    against these keywords: ${keywords.join(“, “)}
    Considering the URL inspection data from Google Search Console:
    ${inspectionData.map(row => `${row[0]}: ${row[1]}`).join(“\n”)}
    Suggest a short list of specific recommendations on how I can improve the page’s SEO. Make sure the recommendations include details such as change this to that, or add something, etc… Be concrete with SEO recommendations.
  `;


  // Display the prompt in G1
  sheet.getRange(‘G1’).setValue(“Prompt Sent to ChatGPT”).setFontWeight(“bold”);
  sheet.getRange(‘G2:G30’).clearContent(); // Clear previous content in column G
  sheet.getRange(‘G2:G30’).merge(); // Merge cells G2:G30
  sheet.getRange(‘G2’).setValue(prompt).setVerticalAlignment(“top”); // Add the prompt and align to top
  sheet.setColumnWidth(7, 400); // Set column G width to 400px


  // Call ChatGPT API
  const analysisResult = callChatGPT(prompt);


  // Display the result in the spreadsheet (Column F)
  sheet.getRange(‘F1’).setValue(“AI Analysis Result”).setFontWeight(“bold”);
  sheet.getRange(‘F2:F30’).clearContent(); // Clear previous content
  sheet.getRange(‘F2:F30’).merge(); // Merge the cells
  sheet.getRange(‘F2’).setValue(analysisResult).setVerticalAlignment(“top”); // Add the AI result and align to top
  sheet.setColumnWidth(6, 400); // Set column F width to 400px


  // Log the response
  log(“AI Analysis Completed: ” + analysisResult);
}

https://script.google.com/home/projects/12hdeVPtEQBTRuCUUkgzbMx6jKrj9ztgoZ2P4zadLAo0ofHBQpfiLqeYB/edit

完了したら、シートに戻って更新し、新しいSearch Console > Fetch GSC Properties を使用します。

使用しているアカウントを選択し、最終的に使用する予定のアプリを選択するように求められるまで、指示に従います。

すべてがうまくいけば、それをまとめ、新しいスクリプトを使用して最初の SEO 分析を実行するという楽しい部分に進むことができます。

スプレッドシート、GSC、ChatGPTツールを組み合わせる

これまで多くのことを行ってきましたが、ツールが実際に動作する様子を見てみましょう。仕組みは次のとおりです。 

  • Search Console > Authorize GSC に移動します
    • GSC に接続されているアカウントを使用していることを確認してください。異なるアカウントでは機能しません。
  • Search Console > Fetch GSC properties に移動します。
    • スプレッドシートの B1 セルに Select GSC property が表示されるようになります。
    • 分析したいドメインを選択し、B1 の URL を選択します。
  • Search Console > Inspect URL に移動します。
    • スプレッドシートに Inspection Results が表示され、カバレッジ、最終クロール日などの情報が確認できます。
  • 最後に、次の操作を実行します
    • Search Console > AI Analyze に移動します。
    • スプレッドシートの AI Analysis Result に結果が表示され、ページの主要要素と改善のための具体的なステップが提示されます。
  • 注意点
    • 指示をそのまま盲目的に従うのではなく、具体的な改善策として活用してください。
  • カスタムデータの追加
    • ChatGPT のプロンプトを変更 したい場合は、スプレッドシートの G2 セル(”Prompt Sent to ChatGPT” の下)を編集してください。

これで SEO 分析を効率化するスクリプトが完成!

GSC、Google スプレッドシート、ChatGPT を組み合わせることで、ページの最適化により多くの時間を費やせるようになります。

スクリプトを試しながら、自分に合った使い方を見つけてください!

詳しく見る: SEO に使用すべき 15 個の AI ツール

  • Facebook
  • X
  • はてなブックマーク
  • pocket
  • LINE
  • URLをコピー
    URLをコピーしました!

編集者情報

  • X
  • Facebook

アイオイクス SEO Japan編集部

2002年設立から、20年以上に渡りSEOサービスを展開。支援会社は延べ2,000社を超える。SEO/CRO(コンバージョン最適化)を強みとするWebコンサルティング会社。日本初のSEO情報サイトであるSEO Japanを通じて、日本におけるSEOの普及に大きく貢献。

メディアTOPに戻る

RECRUIT

一緒に働く人が大事な今の時代だからこそ、実力のある会社で力をつけてほしい。
自分を成長させたい人、新しいチャレンジが好きな人は、いつでも歓迎します。