【GAS】Yahoo広告の運用データをスプレッドシートに自動取得する方法(v19対応)

2021年9月30日

2025年更新:本記事はv19対応の解説に更新しました。コードサンプルは順次更新予定です。

Yahoo!広告のインプレッション数・クリック数・コンバージョン数・費用などの運用データを、毎日手作業で確認するのは手間がかかります。本記事では GAS(Google Apps Script) を使って、Yahoo!広告のデータをスプレッドシートへ自動で取得・蓄積する方法を解説します。

Yahoo!広告 APIの最新バージョンは v19 です。旧バージョン(v7など)はサポートが終了しているため、これから実装する方はv19をご利用ください。

詳細な仕様はこちらの公式ドキュメントを参照してください。

Yahoo! Ads API 公式ドキュメント

その他の広告媒体の取得方法

Yahoo!広告アプリケーションの登録

Yahoo!広告 API管理ツールにアクセスし、広告運用を行っているYahoo!ビジネスIDでログインします。

「アプリケーションを追加」からアプリケーションを新規登録します。

登録画面で必要事項を入力して確認を選択します。リダイレクトURIには「oob」を入力してください。

登録完了後、クライアントIDクライアントシークレット が表示されるのでメモしておきます。

認証コードの取得

以下の形式でURLを作成してブラウザでアクセスします。

  • CLIENT_ID:登録したクライアントID
  • REDIRECT_URI:アプリケーション登録時に設定したURL
  • THIS_VALUE_SHOULD_BE_UNIQUE_PER_REQUEST:任意の文字列(乱数でOK)
https://biz-oauth.yahoo.co.jp/oauth/v1/authorize?response_type=code
&client_id=CLIENT_ID
&redirect_uri=REDIRECT_URI
&scope=yahooads
&state=THIS_VALUE_SHOULD_BE_UNIQUE_PER_REQUEST

ブラウザでアクセスしてアクセス許可を承認すると、認可コードが画面に表示されます。この値をメモします。

アクセストークン・リフレッシュトークンの取得

ターミナルから下記のcurlコマンドを実行します。

  • CLIENT_ID:クライアントID
  • CLIENT_SECRET:クライアントシークレット
  • REDIRECT_URI:登録時に設定したURL
  • AUTH_CODE:先ほど取得した認可コード
curl -X GET \
https://biz-oauth.yahoo.co.jp/oauth/v1/token?grant_type=authorization_code
&client_id=CLIENT_ID
&client_secret=CLIENT_SECRET
&redirect_uri=REDIRECT_URI
&code=AUTH_CODE

レスポンスに アクセストークンリフレッシュトークン が含まれているのでメモします。

アクセストークンは 1時間で失効 するため、GASではリフレッシュトークンを使って毎回新しいアクセストークンを取得する実装にします。

スプレッドシートとGASの作成

スプレッドシートを作成し、「db」という名前のシートを追加します。

「ツール」→「スクリプトエディタ」からGASを作成します。

✅ 以下のコードは v19 対応版です。clientIdclientSecretrefreshTokenmccAccountIdtargetAccountId を設定してご利用ください。

/**
 * Yahoo!広告 検索広告 API v19 対応版
 */
function main() {
  const ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('db');
  if (!ss) throw new Error("シート 'db' が見つかりません。");

  // --- 設定情報 ---
  const clientId = "****";
  const clientSecret = "****";
  const refreshToken = "****";

  // MCCアカウントを利用する場合
  const mccAccountId = "****"; // MCCアカウントID(x-z-base-account-id用)
  const targetAccountId = "****"; // データを取得したい広告アカウントID

  // 1. アクセストークン取得 (POST)
  const accessToken = yahooAdLogin(clientId, clientSecret, refreshToken);

  // 2. レポート作成ジョブの追加 (v19)
  const reportName = "Search_Report_" + Utilities.formatDate(new Date(), "JST", "yyyyMMdd_HHmmss");
  const createReportResponse = yahooAdCreateSearchReport(accessToken, mccAccountId, targetAccountId, reportName);
  const reportJobId = createReportResponse.rval.values[0].reportDefinition.reportJobId;
  console.log(`Search Report Job Created: ${reportJobId}`);

  // 3. レポート作成完了までループで確認 (最大2分)
  let isCompleted = false;
  for (let i = 0; i < 12; i++) {
    isCompleted = yahooAdCheckSearchReportStatus(accessToken, mccAccountId, targetAccountId, reportJobId);
    if (isCompleted) break;
    console.log("レポート作成中... (10秒待機)");
    Utilities.sleep(10000);
  }

  if (!isCompleted) throw new Error("レポート作成がタイムアウトしました。");

  // 4. レポートの取得とパース
  const reportData = yahooAdDownloadSearchReport(accessToken, mccAccountId, targetAccountId, reportJobId);

  if (reportData && reportData.length > 0) {
    const lastRow = ss.getRange("B:B").getValues().filter(String).length;
    const targetRow = lastRow + 1;
    ss.getRange(targetRow, 1, reportData.length, reportData[0].length).setValues(reportData);
    console.log(`${reportData.length}件のデータを追記しました。`);
  } else {
    console.log("対象期間にデータがありませんでした。");
  }
}

/** 共通ヘッダー生成 */
function getSearchHeaders(accessToken, mccAccountId) {
  return {
    'Authorization': `Bearer ${accessToken}`,
    'x-z-base-account-id': mccAccountId,
    'Content-Type': 'application/json'
  };
}

/** 認証: アクセストークン取得 */
function yahooAdLogin(clientId, clientSecret, refreshToken) {
  const url = "https://biz-oauth.yahoo.co.jp/oauth/v1/token";
  const options = {
    method: 'post',
    payload: {
      grant_type: "refresh_token",
      client_id: clientId,
      client_secret: clientSecret,
      refresh_token: refreshToken,
    }
  };
  const response = UrlFetchApp.fetch(url, options);
  return JSON.parse(response.getContentText()).access_token;
}

/** 検索広告レポート作成 (v19) */
function yahooAdCreateSearchReport(accessToken, mccAccountId, targetAccountId, reportName) {
  const url = "https://ads-search.yahooapis.jp/api/v19/ReportDefinitionService/add";
  const payload = {
    accountId: targetAccountId,
    operand: [{
      reportName: reportName,
      reportType: "CAMPAIGN",
      reportDateRangeType: "YESTERDAY",
      reportDownloadFormat: "CSV",
      reportDownloadEncode: "UTF8",
      reportLanguage: "JA",
      reportCompressType: "NONE",
      reportIncludeDeleted: "TRUE",
      fields: [
        "CAMPAIGN_NAME", "DAY", "CLICKS", "CONVERSIONS", "COST",
        "IMPS", "CLICK_RATE", "AVG_CPC", "CONV_RATE", "CONV_VALUE"
      ]
    }]
  };
  const options = {
    method: 'post',
    headers: getSearchHeaders(accessToken, mccAccountId),
    payload: JSON.stringify(payload),
    muteHttpExceptions: true
  };
  const response = UrlFetchApp.fetch(url, options);
  const json = JSON.parse(response.getContentText());
  if (response.getResponseCode() !== 200) throw new Error("Create Error: " + response.getContentText());
  return json;
}

/** 検索広告レポートステータス確認 (v19) */
function yahooAdCheckSearchReportStatus(accessToken, mccAccountId, targetAccountId, reportJobId) {
  const url = "https://ads-search.yahooapis.jp/api/v19/ReportDefinitionService/get";
  const options = {
    method: 'post',
    headers: getSearchHeaders(accessToken, mccAccountId),
    payload: JSON.stringify({ accountId: targetAccountId, reportJobIds: [reportJobId] })
  };
  const response = UrlFetchApp.fetch(url, options);
  const status = JSON.parse(response.getContentText()).rval.values[0].reportDefinition.reportJobStatus;
  if (status === "COMPLETED") return true;
  if (status === "FAILED") throw new Error("レポート作成失敗");
  return false;
}

/** 検索広告レポートダウンロードと整形(最適化版) */
function yahooAdDownloadSearchReport(accessToken, mccAccountId, targetAccountId, reportJobId) {
  const url = "https://ads-search.yahooapis.jp/api/v19/ReportDefinitionService/download";
  const options = {
    method: 'post',
    headers: getSearchHeaders(accessToken, mccAccountId),
    payload: JSON.stringify({ accountId: targetAccountId, reportJobId: reportJobId })
  };
  const response = UrlFetchApp.fetch(url, options);
  const csvData = Utilities.parseCsv(response.getContentText());
  if (csvData.length <= 1) return [];
  csvData.shift();
  return csvData.filter(row =>
    row.length > 0 && row[0] !== "" && row[0] !== "Total" && row[0] !== "合計"
  ).map(row => [
    row[0], row[1],
    Number(row[2]) || 0, Number(row[3]) || 0, Number(row[4]) || 0,
    Number(row[5]) || 0, row[6],
    Number(row[7]) || 0, row[8],
    Number(row[9]) || 0
  ]);
}

取得期間の設定について

reportDateRangeType の値を変更することで取得対象期間を切り替えられます。

TODAY 本日
YESTERDAY 昨日
LAST_7_DAYS 本日を除く過去7日間
LAST_14_DAYS 本日を除く過去14日間
LAST_30_DAYS 本日を除く過去30日間
LAST_WEEK 先週の月曜日〜日曜日
LAST_BUSINESS_WEEK 先週の月曜日〜金曜日(5営業日)
THIS_MONTH 当月(本日含む)
LAST_MONTH 前月
ALL_TIME 取得可能な全期間

実行方法

GASのエディタで main 関数を選択して「実行」ボタンを押します。初回はGoogleアカウントの承認が必要です。

実行が完了すると、「db」シートに前日分のキャンペーンデータが1行追加されます。毎日自動で取得したい場合は、トリガーを設定して定期実行してください。

  • 「トリガー」→「トリガーを追加」
  • 関数:main
  • イベントのソース:時間主導型
  • 時間の間隔:日タイマー(例:午前6〜7時)

よくある質問

v7のコードをv19に移行するには?

APIエンドポイントの /api/v7/ の部分を /api/v19/ に変更します。レスポンスの構造に変更がある場合は公式のマイグレーションガイドを参照してください。

エラー「HttpRequestError」が出る場合は?

アクセストークンの有効期限(1時間)が切れている可能性があります。リフレッシュトークンを使って新しいアクセストークンを取得してから再実行してください。また、クライアントID・シークレット・アカウントIDの設定値を再確認してください。

取得できるデータ項目を増やすには?

fields 配列に項目名を追加します。利用可能なフィールド一覧は公式APIリファレンスで確認できます。

スプレッドシートのシート名を変えたい場合は?

コード冒頭の getSheetByName('db')'db' を任意のシート名に変更してください。

GAS,Javascript

Posted by Next-k