Yahoo!広告 スクリプト | Developer Center
English審査落ちキーワードの通知
スクリプトの概要
本ページでは、審査落ちしたキーワードがあった場合に、該当のキーワードの情報をGoogleスプレッドシートへ一覧で出力し、出力結果をメールまたはSlackで通知できるスクリプトをご紹介します。
本機能をご利用いただくことで、広告管理ツール上で確認するしかなかった審査落ち理由も含めてGoogleスプレッドシート上で一覧で確認できるため、キーワードの審査結果の確認工数が減少し運用の効率化が図れます。
キーワードの審査状況のステータスについて
審査状況のステータスについてについては、こちらのヘルプをご覧ください。
以下の項目が出力されます。
日(スクリプト実行日) |
キャンペーンID |
キャンペーン名 |
広告グループID |
広告グループ名 |
キーワードID |
キーワード |
マッチタイプ |
配信設定 |
審査状況 |
審査落ち理由 |
最終リンク先URL |
ご利用の流れ
1.Yahoo!広告スクリプトとGoogleアカウントを連携します
詳しくはGoogleアカウントとの連携を確認してください。
※すでに連携済みの方は次のステップからご設定ください。
2.連携したGoogleアカウントにて、審査落ちキーワードを出力するGoogleスプレッドシートを新規作成してください。
作成したスプレッドシートIDを確認してメモしておいてください。スクリプト内の定数の設定で利用します。
※GoogleスプレッドシートIDの取得方法についてはこちらをご覧ください。
3.管理画面上のスクリプト作成画面にて、後述のサンプルコードを設定してください。
※スクリプトの新規作成および編集の手順はこちらをご覧ください。
4.管理画面上にてスクリプトの設定を完了後、必要に応じてスクリプトの実行頻度の設定をしてください。
本スクリプトでは1日1回(時間は任意)の設定が推奨です。
※スクリプトの実行頻度の設定手順はこちらをご覧ください。
サンプルコード内各定数のご説明
後述のサンプルコードにおける各定数の設定方法についてご説明いたします。■スプレッドシートID、シート名の指定例
次の例のように、' '(シングルクオーテーション)で囲んで指定してください。(スプレッドシートID:'12345abcde'、シート名:'Sheet1'の場合)const SPREAD_SHEET_ID = '12345abcde';
const SHEET_NAME = 'Sheet1';
■チェック対象のキーワードの配信状況について
審査落ちをチェックする対象とするキーワードの配信状況を指定可能です。ご利用状況に合わせていずれかをご指定ください。const TARGET_AD_STATUS = 'BOTH';// BOTH:両方、ACTIVE:配信オンのみ、PAUSED:配信オフのみ
■通知の頻度の指定について
スクリプトの実行結果を通知する頻度を指定できます。ご利用状況に合わせていずれかをご指定ください。通知の頻度 | 解説 |
---|---|
ON_ADDED | 前回のスクリプト実行後、追加で審査落ちキーワードがある場合のみ通知します |
ALWAYS | スクリプトの実行後、毎回通知します |
NONE | 通知自体しません |
const ALERT_TYPE = 'ON_ADDED';// ON_ADDED:追加がある場合のみ、ALWAYS:毎回実行後、NONE:通知自体しない
ご注意
通知の頻度を「NONE」にしていても、スクリプトの実行エラーの場合はメール/Slack通知されます。
実行エラーの場合も通知が不要の場合は、メール、Slackの指定例を参考にFLAG_MAILとFLAG_SLACKを両方falseにしてください。
■メール、Slackの指定例
メール、Slack設定についてをご確認ください。サンプルコード
下記のスクリプトを、「コピー」ボタンを押してコピーし、スクリプトの入力画面に貼り付けてください。(このとき、灰色のコメント部分は消さずに残しておいてください)「サンプルコード内各定数のご説明」またはスクリプト内に記載の利用方法に沿って、設定が必要な定数を設定してください。
/*このソースコードは MIT License のもとで提供されています。
https://ads-developers.yahoo.co.jp/ja/ads-script/post/30418913.html
■スクリプト内容
アカウントに、実行時点で指定した配信状況の審査落ちのキーワードがあった場合にメール/Slack通知します。
■利用方法
1.当スクリプトを、検索広告のアカウントに設定してください。
2.定数を以下のように設定してください。
3.実行頻度を1日1回(時間は任意)に設定してください。
■定数
・SPREAD_SHEET_ID //スプレットシートIDを指定
・SHEET_NAME //出力シート名
・TARGET_KW_STATUS //抽出対象とするキーワードの配信状況。BOTH:両方、ACTIVE:配信オンのみ、PAUSED:配信オフのみ。
・ALERT_TYPE //通知の頻度。ON_ADDED:追加がある場合のみ、ALWAYS:毎回実行後、NONE:通知自体しない。
※NONEにしていても、実行エラーの場合はメール/Slack通知されます。
実行エラーの場合も通知しなくていい場合は、FLAG_MAILとFLAG_SLACKを両方falseにしてください。
・FLAG_MAIL //結果をメール送信するならtrue、しないならfalse
・MAIL_TO //メール送信先のYahoo! BusinessID
・MAIL_TITLE //メールタイトル
・FLAG_SLACK //結果をSlack送信するならtrue、しないならfalse
・URL_FETCH_APP //SlackのWebhook URL
■制限事項
・取得できる審査落ちのKWは、1万件が上限となります。
*/
//設定が必要な定数
const SPREAD_SHEET_ID = 'SPREAD_SHEET_ID';
const SHEET_NAME = 'SHEET_NAME';
const TARGET_KW_STATUS = 'BOTH';// BOTH:両方、ACTIVE:配信オンのみ、PAUSED:配信オフのみ
const ALERT_TYPE = 'ON_ADDED';// ON_ADDED:追加がある場合のみ、ALWAYS:毎回実行後、NONE:通知自体しない
const FLAG_MAIL = false;
const MAIL_TO = ['Yahoo! JAPAN Business ID'];
let MAIL_TITLE = '審査落ちキーワード通知';
const FLAG_SLACK = false;
const URL_FETCH_APP = 'SLACK_WEBHOOK_URL';
//設定が不要な定数(変更するとエラーになります)
const accountId = AdsUtilities.getCurrentAccountId();
const productType = AdsUtilities.getProductType();
let TEXT_MESSAGE_ARRAY = [];
const SPREAD_SHEET_URL = 'https://docs.google.com/spreadsheets/d/' + SPREAD_SHEET_ID;
const SS_HEADER = ['日', 'キャンペーンID', 'キャンペーン名', '広告グループID', '広告グループ名',
'キーワードID', 'キーワード', 'マッチタイプ', '配信設定', '審査状況', '審査落ち理由', '最終リンク先URL'];
const keywordIdColIdx = 5;//並び順変えたとき対策
function main() {
try {
if (productType == 'MCC' || productType == 'DISPLAY') {
throw new Error('このスクリプトは検索広告アカウントでのみ実行できます');
}
//審査落ちキーワードを取得
const disapprovalKeywords = getDisapprovalKeywords();
if (disapprovalKeywords != null && disapprovalKeywords.length > 0) {
//対象がある場合のみ出力・通知
const addCnt = outputdisapprovalKeywordsToSS(disapprovalKeywords);
if (ALERT_TYPE == 'ALWAYS'//毎回通知は常に通知
|| (ALERT_TYPE == 'ON_ADDED' && addCnt > 0)//追加がある場合のみ通知
) {
sendMailAndSlack();
}
} else {
Logger.log('審査落ちキーワードはありませんでした。');
}
} catch (error) {
MAIL_TITLE = '!!エラー発生!!' + MAIL_TITLE;
logAndMessage('!!エラーが発生しました!!詳細は管理画面のログをご確認ください。' + error);
sendMailAndSlack();
throw Error(error);
}
}
//マスタから審査落ちキーワードを取得
function getDisapprovalKeywords() {
const operand = {
accountId: accountId,
numberResults: 10000,
approvalStatuses: [
'PRE_DISAPPROVED', 'POST_DISAPPROVED',
],
use: 'BIDDABLE',
userStatuses: [TARGET_KW_STATUS]
};
if (TARGET_KW_STATUS == 'BOTH') {
//両方の場合はuserStatusesで絞らない
delete operand.userStatuses;
}
const criterions = Search.AdGroupCriterionService.get(operand).rval.values;
Logger.log('対象データを取得しました');
return criterions;
}
//スプレッドシートに審査落ちキーワードを出力する
function outputdisapprovalKeywordsToSS(disapprovalKeywords) {
//出力用データ生成
let outputData = createOutputData(disapprovalKeywords);
Logger.log('出力データ生成が完了しました');
//出力
const ss = validateAndGetSpreadsheet();
const sh = validateAndGetSheet(ss);
const previousSSData = sh.getDataRange().getValues();//前回データ
//ヘッダを付ける前のデータ行だけを比較する
const addCnt = comparePreviousAndCurrent(previousSSData, outputData);
logAndMessage('前回からの追加は' + addCnt + '件です。');
//洗い替え
sh.clear();
outputData.unshift(SS_HEADER);//ヘッダ行を先頭に追加
sh.getRange('A1').setValues(outputData);
logAndMessage('スプレッドシートにデータを出力しました。\n' + SPREAD_SHEET_URL);
return addCnt;
}
//出力データを生成する
function createOutputData(disapprovalKeywords) {
const disapprovalReasonDictArr = getDisapprovalReasons();
const today = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy/MM/dd');
let outputData = [];
for (let i = 0; i < disapprovalKeywords.length; i++) {
const adGroupCriterion = disapprovalKeywords[i].adGroupCriterion;
let titleArray = [];
for (let j = 0; j < adGroupCriterion.biddableAdGroupCriterion.disapprovalReasonCodes.length; j++) {
titleArray.push(disapprovalReasonDictArr[adGroupCriterion.biddableAdGroupCriterion.disapprovalReasonCodes[j]]);
}
outputData.push([
today,
adGroupCriterion.campaignId,
adGroupCriterion.campaignName,
adGroupCriterion.adGroupId,
adGroupCriterion.adGroupName,
adGroupCriterion.criterion.criterionId,
adGroupCriterion.criterion.keyword.text,
getMatchTypeStr(adGroupCriterion.criterion.keyword.keywordMatchType),
(adGroupCriterion.biddableAdGroupCriterion.userStatus == 'ACTIVE') ? 'オン' : 'オフ',
getApprovalStatusStr(adGroupCriterion.biddableAdGroupCriterion.approvalStatus),
titleArray.join(','),
adGroupCriterion.biddableAdGroupCriterion.finalUrl
]);
}
return outputData;
}
//審査落ち理由をDictionaryServiceから取得する
function getDisapprovalReasons() {
const dictionaries = Search.DictionaryService.getDisapprovalReason({
lang: 'JA',
}).rval;
let dictionaryArray = [];
for (let i = 0; i < dictionaries.totalNumEntries; i++) {
let dictionary = dictionaries.values[i].disapprovalReason;
dictionaryArray[dictionary.disapprovalReasonCode] = dictionary.title;
}
return dictionaryArray;
}
//審査状況の文字列生成
function getApprovalStatusStr(approvalStatus) {
switch (approvalStatus) {
case 'PRE_DISAPPROVED':
return '掲載不可';
case 'POST_DISAPPROVED':
return '掲載停止';
default://ないとは思うが
return '';
}
}
function getMatchTypeStr(matchType) {
const matchTypes = {
'EXACT': '完全一致',
'BROAD': 'インテントマッチ',
'PHRASE': 'フレーズ一致'
};
return matchTypes[matchType];
}
//前回と今回を比較して追加された数を取得する
function comparePreviousAndCurrent(previousSSData, outputData) {
previousSSData.shift();//前回スプシ内容全件なので、ヘッダは抜いておく
const previousAdIdSet = createAdIdSet(previousSSData);
const currentAdIdSet = createAdIdSet(outputData);
//比較
let addCnt = 0
currentAdIdSet.forEach(function (currentAdId) {
if (!previousAdIdSet.has(currentAdId)) {
addCnt++;
}
})
return addCnt;
}
//キーワードIDのSetを生成する
function createAdIdSet(ssData) {
let adIdSet = new Set();//重複排除するためSetを使う
for (let i = 0; i < ssData.length; i++) {
const adId = Number(ssData[i][keywordIdColIdx]);
adIdSet.add(adId);
}
return adIdSet;
}
//スプレッドシート部品
function validateAndGetSpreadsheet() {
if (SPREAD_SHEET_ID === 'SPREAD_SHEET_ID' || SPREAD_SHEET_ID === '') {
throw new Error('スプレッドシートIDを設定してください。');
}
try {
return SpreadsheetApp.openById(SPREAD_SHEET_ID);
} catch (e) {
throw new Error('スプレッドシートを開くことが出来ませんでした。スプレッドシートIDまたはスプレッドシートの権限が正しいか確認してください。' + e);
}
}
function validateAndGetSheet(ss) {
if (SHEET_NAME === '') {
throw new Error('シート名を設定してください。');
}
const sh = ss.getSheetByName(SHEET_NAME);
if (sh === null) {
throw new Error('シートが開けませんでした。シート名を確認してください。');
}
return sh;
}
//ログ、メールなどに流すテキスト
function logAndMessage(text) {
Logger.log(text);
TEXT_MESSAGE_ARRAY.push(text);
}
//メール・Slack部品
function sendMailAndSlack() {
validateAndSendSlack();
validateAndSendMail();
}
function validateAndSendSlack() {
if (FLAG_SLACK) {
if (URL_FETCH_APP === 'SLACK_WEBHOOK_URL' || URL_FETCH_APP === '') {
throw new Error('SlackのWebhook URLを設定してください。Slack送信前までに実行された処理は完了しています。');
}
UrlFetchApp.fetch(URL_FETCH_APP, {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify({
text:
'【アカウントID:' + accountId + '】' + MAIL_TITLE + '\n' +//Slackもタイトルがあった方がいい
TEXT_MESSAGE_ARRAY.join('\n'),
}),
});
}
}
function validateAndSendMail() {
if (FLAG_MAIL) {
if (MAIL_TO.length < 1 || !MAIL_TO.every(str => typeof str === 'string' && /^[a-zA-Z0-9]+$/.test(str))) {
throw new Error('Yahoo! JAPANビジネスIDを設定してください。メール送信前までに実行された処理は完了しています。');
}
MailApp.sendEmail({
to: MAIL_TO,
subject: '【アカウントID:' + accountId + '】' + MAIL_TITLE,
body: TEXT_MESSAGE_ARRAY.join('\n')
});
}
}