Yahoo!広告スクリプトを使って祝日のオン・オフを自動化する方法を検証してみた
こんにちは。
待ちに待った!なのか、そうでもないのかは人それぞれでしょうがYahoo!広告スクリプトがリリースされましたね。
ちなみに私は特に待望していたわけではないですが、
サービス提供されたからにはちょっと遊んでみたいと思う次第です。
以前、Google広告とYahoo!広告で祝日オンオフを自動化する記事を公開しました。まだご覧になってない方はぜひ一読ください!
Google広告については「Google Ads Script」を利用し、
Yahoo!広告は「Yahoo!広告API」を使う方法でした。
また、祝日判定には、Google カレンダーAPIを使用しましたね。
GoogleカレンダーAPIを普通に使おうとすると
本来はGoogle Cloud Platformでプロジェクト作って~API有効にして~
OAuth認証まわりのIDとシークレット準備して~
アクセストークンゲットして~云々
という初心者からすると
なかなかハードル高い作業が待っています。
しかし、Google広告の方で使った「Google Ads Script」 や
Yahoo!広告で利用した「Google Apps Script(以降GASと記載)」などを用いると、その辺の面倒なことを全部裏側でやってくれて、サクッとスタートできました。
同じGoogleのプロダクトであることの恩恵ですね!
しかし、、Yahoo!は面倒なことありましたよね!?
Yahoo!広告の面倒だった点
改めて記事を貼るとこちらですが、、(しつこくてすみません)
確かにGoogleカレンダーAPIを利用するのに面倒な認証フェーズはありませんでしたが、最初のYahoo!広告APIを利用するための認証作業がありました。
記事ではササっと書いていますが
ここを読んで「うわっなんかメンドクサ!」と思った人もいるでしょう。
また、代理店の方や、インハウスでも一担当者の方であれば、
「これ自分のYahoo!アカウントでアプリ作成していいのか・・・?」
「色々説明して許可もらうのも大変そう・・・」
みたいな問題もあったかもしれません。
そこで、今回はせっかくなのでYahoo!広告スクリプトを使ってみましょう、という話です。
前段が長くなりましたが早速見ていきましょう!
Yahoo!広告スクリプトで実装するための大まかなアウトライン
どのように連携していくのが良いでしょうか?
Yahoo!広告スクリプトには
「UrlFetchApp」というHTTPリクエストを送るための関数が用意されています。
「じゃあそれでGoogleカレンダーAPIにリクエスト送ればいいじゃーん」
と思うかもしれません。
はい!!その通りです!!
それで出来ます。
~~完~~
ところがButしかし
ちょっと待ってください。
Yahoo!広告スクリプトからGoogleカレンダーAPIへリクエスト送るためには
最初の方でも記載した GoogleカレンダーAPI を使う認証を行う必要があります。
どうせ認証するなら、Yahoo!広告APIを使うための認証をやった方が
Google Cloud Platformのプロジェクトとか作る必要ないし簡単です。
であれば、Yahoo!広告APIを使う方法でやればよく
Yahoo!広告スクリプトで実施する意味があまりない、、(気がする)
ここでもう1つ注目します。
実はYahoo!広告スクリプトは「Google スプレッドシート」とは連携していて、手動で面倒な認証をする手間が省けます。
そして、Googleスプレッドシート(とGAS)からGoogleカレンダーへの連携もめちゃくちゃ簡単です。(Yahoo!広告APIの記事で書いた通り。)
というわけで、
Yahoo!広告スクリプト↔Googleスプレッドシート(GAS)↔Googleカレンダー
をうまく連携させながら設定してみようかなって思います。
間にスプレッドシート入って余計大変になったように見えるかもしれませんが、手動でAPI認証する必要がないのはメリットだと思います。
慣れている人であればたいしたことないですが、
広告運用者やマーケターが全員APIまわりに慣れているとも限りません。
(むしろ慣れてる人の方があまりいないでしょう)
そのような意味では
Yahoo!広告スクリプト↔Googleスプレッドシート(GAS)↔Googleカレンダー
の手法の方が分かりやすく、さくっとできると考えたわけです。
ではまずGoogleスプレッドシート及びGASとGogoleカレンダーAPIの連携を見ていきましょう。
Googleスプレッドシート上で祝日を判定する
Googleスプレッドシートでの準備
まずはスプレッドシートを立ち上げましょう。
適当に名前を付けます。シート名は今回は「day」にしています。
そして、↓こんな↓感じで書いてみます。
A3には「=today()」が入ってます。
で、A2には「=A3-1」、
A4には「=A4+1」を入れます。
要するに「A2が前日」で「A4が翌日」です。
スプレッドシートでやることは以上です。
次はGASですね。
GoogleAppsScriptの準備
ちょっとモチベーション上げるために先に完成形を見せますね!
スクリプトを実行した時に以下のように、祝日ならYes、祝日でなければNoを返すのがゴールです。ついでに祝日の場合は「なんの日」か入れてます。
先程のスプレッドシートの「拡張機能」から「Apps Script」をクリックします。
GASのエディタが開かれると思います。
左上の「無題のプロジェクト」をクリックしてリネームしましょう。
じゃあ早速コードを見ましょう。
function myFunction() {
const calendarId = "ja.japanese#holiday@group.v.calendar.google.com";
const calendar = CalendarApp.getCalendarById(calendarId);
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sh = ss.getActiveSheet(); // 明確に指定するなら、ss.getSheetByName('day')
const yesterday = sh.getRange('A2').getValue();
const today = sh.getRange('A3').getValue();
const tomorrow = sh.getRange('A4').getValue();
const yesterdayArray = calendar.getEventsForDay(yesterday);
const todayArray = calendar.getEventsForDay(today);
const tomorrowArray = calendar.getEventsForDay(tomorrow);
judge(2, yesterdayArray, sh);
judge(3, todayArray, sh);
judge(4, tomorrowArray, sh);
}
function judge(row, array, sh) {
switch(array.length) {
case 0:
sh.getRange(row, 2).setValue('祝日じゃないよ');
sh.getRange(row, 3).setValue('No');
break;
default:
sh.getRange(row, 2).setValue(`祝日です: ${array[0].getTitle()}`);
sh.getRange(row, 3).setValue('Yes');
break;
}
}
以上!
はい、これだけです。
順番に見ていきましょう。
const calendarId = "ja.japanese#holiday@group.v.calendar.google.com";
const calendar = CalendarApp.getCalendarById(calendarId);
カレンダーオブジェクトを生成しています。
GASには「CalendarApp」が用意されており、これでGoogle カレンダーAPIとの連携が簡単に出来るんですね。
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sh = ss.getActiveSheet(); // 明確に指定するなら、ss.getSheetByName('day')
今度はスプレッドシートとの連携です。
こちらも「SpreadsheetApp」が用意されていて簡単です。
シート取得は「getActiveSheet()」を使っていますが、シート名を明記したい場合は「getSheetByName('day')」とします。
const yesterday = sh.getRange('A2').getValue();
const today = sh.getRange('A3').getValue();
const tomorrow = sh.getRange('A4').getValue();
ここはスプレッドシートから値を取得しています。
元々、以下のようなスプレッドシートでしたので、
「A2」には前日、「A3」には当日、「A4」には翌日の日付が記載されていますので、それらを取ってきているわけです。
const yesterdayArray = calendar.getEventsForDay(yesterday);
const todayArray = calendar.getEventsForDay(today);
const tomorrowArray = calendar.getEventsForDay(tomorrow);
上で取得した日付を元に、
祝日カレンダーに登録があるかを見ています。
祝日であれば、戻り値は色々情報の入った配列になります。
祝日でなければ、戻り値は「空の配列」になります。
↑この↑配列の状態を元に祝日かを判定する関数が以下です。
function judge(row, array, sh) {
switch(array.length) {
case 0:
sh.getRange(row, 2).setValue('祝日じゃないよ');
sh.getRange(row, 3).setValue('No');
break;
default:
sh.getRange(row, 2).setValue(`祝日です: ${array[0].getTitle()}`);
sh.getRange(row, 3).setValue('Yes');
break;
}
}
要するに、
祝日じゃない = 空の配列 = サイズが0 ( = array.length = 0)
のときは「No」とスプレッドシートに記載する。
祝日のとき = 配列が空ではない = サイズが0じゃない
場合は、「Yes」を記入する。
ついでにarrayから getTitle()して祝日名も記載する
という動きをしています。
getRange()は先程は「getRange('A2')」のようにセル名を直接入れましたが、
行と列で指定することも可能です。
例えば「B2」であれば、行は2行目、列は2列目なので、「getRange(2, 2)」とも指定できます。
ここでは後者の指定方法で記載しています。
あとは、judge関数を呼び出して判定するだけです。
judge(2, yesterdayArray, sh);
judge(3, todayArray, sh);
judge(4, tomorrowArray, sh);
judge関数は 大元のmyFunction関数とは完全に別で作成している(スコープが異なる)ので、shも引数として渡してあげます。
※何を言っているのかというと
というように、hogeの中に完全にfugaが含まれている場合は、
hogeで宣言した変数がfugaでも使えますが、今回は
と、hogeとfugaを完全に別立てしているので、
hoge内で宣言した変数はfuga内ではそのままでは使えない、という話です。
実行してみる
ここまで来たら、まずGASを保存しましょう。
フロッピーのマークです。
それから実行!!
(わざわざ保存しなくても実行クリックすれば自動で保存もされます)
最初は承認を求められると思います。
Googleカレンダー及び、Googleスプレッドシートと連携するためですね。
本来手動でAPI認証とかごちゃごちゃ必要なところを
パパっと2クリックくらいで自動でやってくれます!
ここが便利なところです。
で、実行したらスプレッドシートに書き込まれると思います。
試しに「=today()」となっているところを
祝日の日に一旦書き換えてみましょう。(下の例では5/5)
ここでGASに戻りもう1度「実行」をクリック!
出来てますね!
試したら、また「=today()」に戻しておきましょう。
なお、スプレッドシートを変更しても判定結果は自動では変わりません。
再びGASの「実行」をクリックしましょう。
今は1回1回「実行」クリックしていますが、
後ほど自動で動くようにトリガーを設定します。
(Yahoo!広告APIの回で記載したのと同様です。)
ここまで来たら、
Yahoo!広告スクリプトの方からGoogleスプレッドシートの値を取得して
YesかNoかで祝日のオンオフするコードを書くだけです。
Yahoo!広告スクリプトの準備
それではYahoo!広告スクリプトの方を見ていきましょう。
広告管理画面に入り、
「ツール > Yahoo!広告スクリプト」
です。
左上に「新規作成」ボタンがありますが、その前にやっておくことがあります。
今回、Google スプレッドシートと連携しますので、
先にそちらの認証処理をしておきましょう。
分かりづらいのですが、右上の方に『外部ツール連携』という項目があります。そこをクリックします。
「Sign in with Google」のボタンをクリックします。
Googleログイン画面が表示されるのでログインします。
承認が求められるので「続行」をクリックすれば連携完了です!
ステータスが「連携済み」になっていれば問題なしです!
ここまで終えたら、今度こそ左上の「新規作成」をクリックしましょう。
そしたら以下のような画面になると思います。
これでスクリプトを書く準備はOK!
翌日が祝日の場合に停止
早速停止の場合から見ていきましょう。
スクリプト名はなんでもいいですが、
ここでは「停止判定」としています。
また、以下のコードは「検索広告(YSA)」のコードになります。
コードは単純で以下です。
function main() {
const spreadsheetId = "<スプレッドシートのID>";
const ss = SpreadsheetApp.openById(spreadsheetId);
const sheetName = "day";
const sh = ss.getSheetByName(sheetName);
getJudge(sh);
}
function getJudge(sh) {
const tomorrow = sh.getRange('C4').getValues();
if(tomorrow[0][0] === 'Yes') {
Logger.log('停止');
pauseCampaign();
} else {
Logger.log('停止しない');
}
}
function pauseCampaign() {
const accountId = AdsUtilities.getCurrentAccountId();
const campaignIds = [00000, 11111];
let campaignArray = [];
for(let campaignId of campaignIds) {
let setCampaign = {
accountId: accountId,
campaignId: campaignId,
userStatus: "PAUSED"
};
campaignArray.push(setCampaign)
}
const campaignSet = Search.CampaignService.set({
accountId: accountId,
operand: campaignArray
}).rval;
campaignSet.values.forEach((campaignObj, index) => {
let campaign = campaignObj.campaign;
if(campaignObj.operationSucceeded) {
Logger.log('campaignId-> ' + campaign.campaignId + ', campaignName-> ' + campaign.campaignName + ' has been paused.');
} else {
let errorList = campaignObj.errors;
errorList.forEach((element) => {
if (element.code == 'I0001' && element.details[0].requestKey.includes('campaignId')) {
Logger.log('campaignId-> ' + element.details[0].requestValue + ' does not exsit.');
} else {
Logger.log('campaignId-> ' + campaignsArray[index].campaignId + ' could not to be stopped.');
}
});
}
});
}
単純と言いつつ、ちょっと長く見えるかもしれませんが、
実は↓ここ↓までのコードで「翌日が祝日か?」の判定は終わってます。
function main() {
const spreadsheetId = "<スプレッドシートのID>";
const ss = SpreadsheetApp.openById(spreadsheetId);
const sheetName = "day";
const sh = ss.getSheetByName(sheetName);
getJudge(sh);
}
function getJudge(sh) {
const tomorrow = sh.getRange('C4').getValues();
if(tomorrow[0][0] === 'Yes') {
pauseCampaign();
} else {
Logger.log('停止しない');
}
}
まず、スプレッドシートのIDというのは、
URLを見た時の「~/d/この部分/edit」です。
d/ と /edit に囲まれた部分ですね。
ここをコピーして記載してください。
さて、スプレッドシートを思い出して欲しいのですが、
「翌日が祝日か祝日でないか」の結果は「C4」のセルに入っています。
なので、C4の文字列を取ってきて
「Yes」なら停止(pauseCampaign()を実行)
※C4がYesということは「翌日が祝日」⇒停止処理※
それ以外(つまり「No」)なら、停止しない、というコードになっています。
なお、GASには「getValue()」というセル単体を値を取得するメソッドがありますが、Yahoo!広告スクリプトでは対応していなく、「getValues()」しかありません。
getValues()の戻り値は二次元配列なので、
tomorrow[0][0]というように中身を取り出す作業があります。
そして、後半の長々しているところが
「キャンペーンを停止するためのコード」です。
こちらも実はキャンペーン停止のリクエストを送るだけであれば、
↓ここまで↓で完了しています。
function pauseCampaign() {
const accountId = AdsUtilities.getCurrentAccountId();
const campaignIds = [10001, 11111];
let campaignArray = [];
for(let campaignId of campaignIds) {
let setCampaign = {
accountId: accountId,
campaignId: campaignId,
userStatus: "PAUSED"
};
campaignArray.push(setCampaign)
}
const campaignSet = Search.CampaignService.set({
accountId: accountId,
operand: campaignArray
}).rval;
Search.CampaignService.set(云々)の段階で停止リクエストは通っています。
↓↓の部分は停止したいキャンペーンIDを記載ください。
(すべてのキャンペーンIDをスクリプトで取得する方法や、
キャンペーンじゃなくてアカウント単位で停止する方法もありますが
今回は割愛します。)
const campaignIds = [10001, 11111];
じゃあ、最後の方は何をしているのかというと、
「ちゃんとエラーが出ないと完了したよ」とか
「こんなエラーでたよ」というのをログに残すためのコードです。
campaignSet.values.forEach((campaignObj, index) => {
let campaign = campaignObj.campaign;
if(campaignObj.operationSucceeded) {
Logger.log('campaignId-> ' + campaign.campaignId + ', campaignName-> ' + campaign.campaignName + ' has been paused.');
} else {
let errorList = campaignObj.errors;
errorList.forEach((element) => {
if (element.code == 'I0001' && element.details[0].requestKey.includes('campaignId')) {
Logger.log('campaignId-> ' + element.details[0].requestValue + ' does not exsit.');
} else {
Logger.log('campaignId-> ' + campaignsArray[index].campaignId + ' could not to be stopped.');
}
});
}
});
ちょっとごちゃついてますが、
成功したら以下のようなログが出ます。
逆に、例えば
そのアカウントに存在しないキャンペーンIDを指定してしまった場合、
以下のようにエラーログが残ります。
以上で、停止処理のスクリプトは完了です。
活用方法は例えば、GASの方の判定コードが
21時-22時くらいに動くように設定しておきます。(方法は後ほど説明します)
するとスプレッドシートの値が更新されます。
そして、Yahoo!広告スクリプトを23時-24時に動く設定などすれば(こちらも後ほど説明します)、明日が祝日かどうか判定した上で、祝日なら停止します。
さて、次は再開のコードに参りましょう。
前日が祝日 かつ 当日が祝日ではない 場合に再開
「新規作成」から再開verを作ります。
名前は何でも良いですが、ここでは「再開判定」にしています。
停止のときと同様に、以下はまず「検索広告」のコードになります。
それでは見ていきましょう。
function main() {
const spreadsheetId = "<スプレッドシートのID>";
const ss = SpreadsheetApp.openById(spreadsheetId);
const sheetName = "day";
const sh = ss.getSheetByName(sheetName);
getJudge(sh);
}
function getJudge(sh) {
const yesterday = sh.getRange('C2').getValues();
const today = sh.getRange('C3').getValues();
if(yesterday[0][0] === "Yes" && today[0][0] === "No") {
Logger.log('再開');
activeCampaign();
} else {
Logger.log('再開なし');
}
}
function activeCampaign() {
const accountId = AdsUtilities.getCurrentAccountId();
const campaignIds = [10001, 11111];
let campaignArray = [];
for(let campaignId of campaignIds) {
let setCampaign = {
accountId: accountId,
campaignId: campaignId,
userStatus: "ACTIVE"
};
campaignArray.push(setCampaign)
}
const campaignSet = Search.CampaignService.set({
accountId: accountId,
operand: campaignArray
}).rval;
campaignSet.values.forEach((campaignObj, index) => {
let campaign = campaignObj.campaign;
if(campaignObj.operationSucceeded) {
Logger.log('campaignId-> ' + campaign.campaignId + ', campaignName-> ' + campaign.campaignName + ' has been active.');
} else {
let errorList = campaignObj.errors;
errorList.forEach((element) => {
if (element.code == 'I0001' && element.details[0].requestKey.includes('campaignId')) {
Logger.log('campaignId-> ' + element.details[0].requestValue + ' does not exsit.');
} else {
Logger.log('campaignId-> ' + campaignsArray[index].campaignId + ' could not to be stopped.');
}
});
}
});
}
コードはだいたい同じですね。
前半は全く同じで、スプレッドシート情報をGETしています。
function main() {
const spreadsheetId = "<スプレッドシートのID>";
const ss = SpreadsheetApp.openById(spreadsheetId);
const sheetName = "day";
const sh = ss.getSheetByName(sheetName);
getJudge(sh);
}
次の判定部分が停止の時とは異なります。
function getJudge(sh) {
const yesterday = sh.getRange('C2').getValues();
const today = sh.getRange('C3').getValues();
if(yesterday[0][0] === "Yes" && today[0][0] === "No") {
Logger.log('再開');
activeCampaign();
} else {
Logger.log('再開なし');
}
}
停止の場合は「翌日」を取得しましたが
再開の場合は「前日」と「当日」を見ています。
前日が祝日 = Yes
かつ
当日が祝日ではない = No
の場合に再開という記述です。
以前までのGoogleやYahoo!の記事でも
何度かお話していますが、ここは「当日が祝日ではない」だけの条件でも問題はないです。
ただ、祝日ではない = 平日なのでほとんど毎日ですよね。
すると余計に「activeCampaign()」の関数が実行されるので、
なんとなく微妙なので避けています。
あくまで、「前日が祝日 = つまり停止している」ときに、
「当日が祝日ではない」なら再開させる、というコードです。
そして、activeCampaign()のコードがこちら。
function activeCampaign() {
const accountId = AdsUtilities.getCurrentAccountId();
const campaignIds = [10001, 11111];
let campaignArray = [];
for(let campaignId of campaignIds) {
let setCampaign = {
accountId: accountId,
campaignId: campaignId,
userStatus: "ACTIVE"
};
campaignArray.push(setCampaign)
}
const campaignSet = Search.CampaignService.set({
accountId: accountId,
operand: campaignArray
}).rval;
campaignSet.values.forEach((campaignObj, index) => {
let campaign = campaignObj.campaign;
if(campaignObj.operationSucceeded) {
Logger.log('campaignId-> ' + campaign.campaignId + ', campaignName-> ' + campaign.campaignName + ' has been active.');
} else {
let errorList = campaignObj.errors;
errorList.forEach((element) => {
if (element.code == 'I0001' && element.details[0].requestKey.includes('campaignId')) {
Logger.log('campaignId-> ' + element.details[0].requestValue + ' does not exsit.');
} else {
Logger.log('campaignId-> ' + campaignsArray[index].campaignId + ' could not to be stopped.');
}
});
}
});
}
停止と異なる点は、userStatusが "ACTIVE" になっているところと、
ログの記述が「has been paused」から「has been active」になっているだけです。
というわけで以上になります!
なお、「ディスプレイ広告」の場合は以下の
Search.CampaignService.set~ の部分を
Display.CampaignService.set~ にするだけです。
const campaignSet = Search.CampaignService.set({
accountId: accountId,
operand: campaignArray
}).rval;
ここまでで、コードの話はおしまいです。
最後にトリガー設定を少し見ていきましょう。
コードを動かすタイミング
最後、トリガー(コードを動かすタイミング)の話をしていきます。
ざっくり書くと
GASのコードを実行
⇒ スプレッドシートが更新
⇒ Yahoo!広告スクリプトの実行
という流れですね。
Googleスプレッドシートが更新されていないのに
Yahoo!広告スクリプトが動いちゃいけないですよね。
停止側のトリガー
まずGASのコードを「22時~23時」に更新しましょう。
※これについては「その日」ならいつでもいいので、「0時~23時」の間ならいつでもいいです。
GASの「トリガー」をクリックします。
「トリガーを追加」をクリック。
関数を選択して(ここでは myFunction)、
日付ベースのタイマーから時刻を「午後10時~11時」を選択して、
保存します。
これで、22時~23時の間に実行されて、Googleスプレッドシートが更新されます。
次にYahoo!広告スクリプトの方へいきます。
停止判定における「実行頻度」の鉛筆マークをクリックします。
毎日 23:00 にして保存します。
すると、以下のようになります。
GASが22時~23時に動き、
Yahoo!広告スクリプトが23時に動くので
おそらく問題はないのですが、
もしかしたらGASコードが動く前にYahoo!広告スクリプトが動く可能性もゼロではないかもしれません。
心配な方はGASの方のトリガーを
21時~22時(午後9時~10時)にすればOKかと思います。
再開のトリガー
再開の方は、
GASは午前0-1時の間に実行
Yahoo!広告スクリプトは1時に実行
というトリガーを作っていきましょう。
こちらもギリギリが怖い人は、
Yahoo!広告スクリプトの実行を「2時」にしましょう。
では、GASからいきます。
先程と同様に「トリガーを追加」をクリック
設定はほぼ「停止」のときと同様ですが、
時刻だけ「午後0時~1時」にします。
最後に、Yahoo!広告スクリプトの再開判定の実行頻度です。
先程と同様に実行頻度の「未設定」をクリック。
そして、「毎日 1:00」にすればOKです。
前述したように
GASが 午前0時~1時に動き
Yahoo!広告スクリプトが1時に動くので
心配な方はYahoo!広告スクリプトの方を「2時」に動くようにしておくと良いかと思います。
設定を終えるとこんな画面になっているかと思います。
今回の話は以上になります!
Bye, bye.
広告運用に関して詳しくお話を聞きたいという企業様がいらっしゃいましたら、こちらからお問い合わせをお願い致します。
もし、私たちの会社で働く事に少しでも興味を持っていただけたら、ぜひ応募フォームよりご連絡ください。
この記事が気に入ったらサポートをしてみませんか?