Google AdWordsキャンペーンオートメーションの合理化

背景



すべては「AdWordsのxmlアップロードを行う」という言葉から始まり、それから始まりました。 奇妙なことに、このタスクは非常に迅速に完了しましたが、さらに興味深いものでした。 判明したように、AdWordsには、キャンペーンプロセスを自動化するスクリプト(javascript)を書く機会がありました。時間制限とxmlがなければ、すべてうまくいきます。 はい、まさにxmlです。 なぜ誰もがこの形式に夢中になっているのかはわかりませんが、好きではありません。 私はタスクの95%に対処しましたが、率直に言って、私はそれから何の喜びも得ませんでしたが、それでもタスクの5%は残っていました。 xmlではなくjsonに投げたのはこれらの5%で、ここで楽しくなりました。



より詳細



これが何であるかを具体化しましょう。 約25,000のアイテムがあるオンラインストアがあります。 マーケティング担当者は、広告グループ、アナウンス自体、キーなどを作成するために、すべてをキャンペーンに取り込むためにアンロードする必要があります。 後で判明したように、入力データの形式(xml / json)は重要ではないため、好みのjsonを選択しました。



{ elems: [ { id: 555233, n: "Agent Provocateur Maitresse", p: 346, u: "http://site.ua/555233.html", v: "Agent Provocateur", c: " " }, { id: 559675, n: "Angel Schlesser Essential for Men", p: 191, u: "http://site.ua/559675.html", v: "Angel Schlesser", c: " " } ]}
      
      







そして、構造id、n(名前)、p(価格)、u(Url)、v(ベンダー)、c(カテゴリー)のN個の要素があります。いずれにしても、これはまさに必要なデータです。 自動化を始めますか?



スクリプト1.広告グループの作成



 //  google-       var doc = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/15_W4y3GpivCjuNRWPN8HKy27MjtUeW2NTThAAPPXdkc/edit#gid=0'); //     var sheet = doc.getSheetByName('parfums'); // ,         var i_cell = sheet.getRange('B2'); var date_cell = sheet.getRange('B3'); function main() { var i_cell_val = ( i_cell.isBlank() ) ? 0 : i_cell.getValue(); //  JSON var json = JSON.parse(UrlFetchApp.fetch('http://site.ua/adwords.json').getContentText()); //      var tmp = AdWordsApp.campaigns().withCondition('Name = ""').get(); var unloaded = json.elems; var export_l = unloaded.length; if(is_exported()) { Logger.log('Already exported'); return; } if (tmp.hasNext()) { var campaign = tmp.next(); } else { Logger.log('Company not found'); return; } for (i= i_cell_val; i<=export_l-1; i++) { el = unloaded[i]; var tmp = campaign.adGroups().withCondition('Name CONTAINS "__ID-' + el.id +'"').get(); if (tmp.hasNext()) { var tmp_g = tmp.next(); tmp_g.enable(); } else { var adGroupName = el.c + '_' + el.v + '_' + el.n + '__ID-' + el.id; addAdGroup(adGroupName, campaign); } i_cell.getValue(); i_cell.setValue(i); if (i == export_l-1) { date_cell.setValue(Utilities.formatDate(new Date(), "GMT+3", "dMyyyy")); i_cell.setValue(0); } } } function addAdGroup(adGroupName, ci) { var adGroup = ci.newAdGroupBuilder(); adGroup = adGroup.withName(adGroupName).withStatus("ENABLED").withKeywordMaxCpc(1).create(); } function is_exported() { var exp_date = Number(Utilities.formatDate(new Date(date_cell.getValue()), "GMT+3", "dd")); var today = Utilities.formatDate(new Date(), "GMT+3", "dd HH").split(' '); if (Number(today[1]) < 6) return true; if ( (exp_date < Number(today[0])) || date_cell.isBlank()) return false; else return true; }
      
      







このスクリプトは、以下を理解するためのヤギになります。 誰が脚本に目を向けたのか、明らかに「なぜ?」 Googleドックがあるのはなぜですか? どんなナンセンス?」 教えて 私がGoogleをどれほど愛していても、悲しいかな、これらの自動化スクリプトは非常に長く実行され、スケジュールは非常にきついです。それが松葉杖の存在です。



なぜGoogleドックが必要なのですか?


Google Dockのスプレッドシートは、説明およびサポートされているAPIがあるアクセス用のリポジトリになります。 そこで、他の何かを実行する必要があるかどうか、または中断する価値があるかどうかをスクリプトが理解するためのデータを書き込みます。



プレートは次のようになります。



画像



セルB2-ここでは、ループ内の要素の現在の反復子を記述します。 すべてが現在の日にアンロードされるとゼロになります。セルB3の値も現在の日付に等しくなければなりません。これらの等式の合計は、すべての要素が今日にアンロードされることを意味します。 これは何のためですか? スクリプトを1時間ごとにスケジュールに入れることができるように、実行が完了すると「Everything is unloaded」というメッセージが表示されてオフになりました。



is_exported関数とは何ですか?


この関数はすべてのスクリプトに存在し、新しいデータですべてのデータを駆動する必要があるかどうかを確認します。

私の場合、具体的には次のようになります。



 function is_exported() { var exp_date = Number(Utilities.formatDate(new Date(date_cell.getValue()), "GMT+3", "dd")); var today = Utilities.formatDate(new Date(), "GMT+3", "dd HH").split(' '); if (Number(today[1]) < 6) return true; if ( (exp_date < Number(today[0])) || date_cell.isBlank()) return false; else return true; }
      
      







これを自分にコピーするときは、いくつかの重要な点を忘れないでください。 まず、タイムゾーンを設定し、GMT + 3を設定します。次に、スクリプトの実行後、「CLOCK」値6ではなくif(Number(today [1])<6)をここに入力します。 およそ、その時間までにアンロード全体の準備が整うので、私には6時間あります。



スクリプト2.グループでのメッセージテキストの作成



 //  google-       var doc = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/15_W4y3GpivCjuNRWPN8HKy27MjtUeW2NTThAAPPXdkc/edit#gid=0'); var sheet = doc.getSheetByName('parfums'); // ,         var i_cell = sheet.getRange('C2'); var date_cell = sheet.getRange('C3'); function main() { var i_cell_val = ( i_cell.isBlank() ) ? 0 : i_cell.getValue(); //  JSON var json = JSON.parse(UrlFetchApp.fetch('http://site.ua/adwords.json').getContentText()); //      var tmp = AdWordsApp.campaigns().withCondition('Name = ""').get(); var unloaded = json.elems; var export_l = unloaded.length; if(is_exported()) { Logger.log('Already exported'); return; } if (tmp.hasNext()) { var campaign = tmp.next(); } else { Logger.log('Company not found'); return; } for (i= i_cell_val; i<=export_l-1; i++) { el = unloaded[i]; var tmp_g = campaign.adGroups().withCondition('Name CONTAINS "__ID-' + el.id +'"').get(); if (tmp_g.hasNext()) { var adGroup = tmp_g.next(); var lb = adGroup.labels().withCondition('Name = "with_text"').get(); //    ADG if (!lb.hasNext()) { //   ADG  ,   adGroup.createTextAd('{KeyWord: }', '   {param1: ' + el.p + '} ', '  !', 'site.ua/' + el.v.replace(/ /g, '_'), el.u); adGroup.applyLabel('with_text'); } } else { Logger.log("  '" + el.id + "'  ."); } i_cell.getValue(); i_cell.setValue(i); if (i == export_l-1) { //   date_cell.setValue(Utilities.formatDate(new Date(), "GMT+3", "dMyyyy")) i_cell.setValue(0); } } } function is_exported() { var exp_date = Number(Utilities.formatDate(new Date(date_cell.getValue()), "GMT+3", "dd")); var today = Utilities.formatDate(new Date(), "GMT+3", "dd HH").split(' '); if (Number(today[1]) < 8) return true; if ( (exp_date < Number(today[0])) || date_cell.isBlank()) return false; else return true; }
      
      







このスクリプトでは、すべての人がすべてを理解していると思いますが、同時に1つのポイントを説明する価値があります-ショートカットの使用です。 なんで? はい、単にグループ内に広告が存在するかどうかを確認する方法を見つけられなかったからです。 グループ内のラベルが見つかった場合、それが存在することを意味します。 テキストを追加した後にのみラベルを割り当てます。 すべてがシンプルです。



スクリプト3.キーワードの作成



 //  google-       var doc = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/15_W4y3GpivCjuNRWPN8HKy27MjtUeW2NTThAAPPXdkc/edit#gid=0'); var sheet = doc.getSheetByName('parfums'); // ,         var i_cell = sheet.getRange('D2'); var date_cell = sheet.getRange('D3'); var flag_cell = sheet.getRange('D4'); function main() { var i_cell_val = ( i_cell.isBlank() ) ? 0 : i_cell.getValue(); //  JSON var json = JSON.parse(UrlFetchApp.fetch('http://site.ua/adwords.json').getContentText()); //      var tmp = AdWordsApp.campaigns().withCondition('Name = ""').get(); var unloaded = json.elems; var export_l = unloaded.length; if(is_exported()) { Logger.log('Already exported'); return; } if (tmp.hasNext()) { var campaign = tmp.next(); } else { Logger.log('Company not found'); return; } var flag_v = ( flag_cell.isBlank() ) ? 1 : flag_cell.getValue(); for (i= i_cell_val; i<=export_l-1; i++) { el = unloaded[i]; var tmp_g = campaign.adGroups().withCondition('Name CONTAINS "__ID-' + el.id +'"').get(); if (tmp_g.hasNext()) { var adGroup = tmp_g.next(); var key = el.n; var tmp_key = AdWordsApp.keywords().withCondition('Text = "' + key + '"').get(); //      if (!tmp.hasNext()) { adGroup.createKeyword(key); } key = '[' + el.n + ']'; tmp = AdWordsApp.keywords().withCondition('Text = "' + key + '"').get(); if (!tmp.hasNext()) { adGroup.createKeyword(key); } } else { flag_v = 0; Logger.log("  '" + el.id + "'  ."); } i_cell.getValue(); i_cell.setValue(i); flag_cell.setValue(flag_v); if (i == export_l-1) { //   if (Number(flag_v)) //     ADG date_cell.setValue(Utilities.formatDate(new Date(), "GMT+3", "dMyyyy")); i_cell.setValue(0); } } } function is_exported() { var exp_date = Number(Utilities.formatDate(new Date(date_cell.getValue()), "GMT+3", "dd")); var today = Utilities.formatDate(new Date(), "GMT+3", "dd HH").split(' '); if (Number(today[1]) < 8) return true; if ( (exp_date < Number(today[0])) || date_cell.isBlank()) return false; else return true; }
      
      







ここでも、すべてが簡単です。 アンロードがあり、IDでグループをプルします。グループ内でキーを作成します。 カーテン! しかし、ここには些細なことはありません。 flag_v変数がここに表示されました。 ゼロの場合、サイクルの動作は終了しません。 これは、広告グループがまだ作成されていない場合に、rassynchronを回避するために行われます。 そのため、is_exported関数の「HOUR」パラメーターを変更し、1時間または2時間後に設定します。



スクリプト4.パラメーターの更新



 //  google-       var doc = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/15_W4y3GpivCjuNRWPN8HKy27MjtUeW2NTThAAPPXdkc/edit#gid=0'); var sheet = doc.getSheetByName('parfums'); // ,         var i_cell = sheet.getRange('E2'); var date_cell = sheet.getRange('E3'); var flag_cell = sheet.getRange('E4'); function main() { var i_cell_val = ( i_cell.isBlank() ) ? 0 : i_cell.getValue(); //  JSON var json = JSON.parse(UrlFetchApp.fetch('http://site.ua/adwords.json').getContentText()); //      var tmp = AdWordsApp.campaigns().withCondition('Name = ""').get(); var unloaded = json.elems; var export_l = unloaded.length; if(is_exported()) { Logger.log('Already exported'); return; } if (tmp.hasNext()) { var campaign = tmp.next(); } else { Logger.log('Company not found'); return; } var flag_v = ( flag_cell.isBlank() ) ? 1 : flag_cell.getValue(); for (i= i_cell_val; i<=export_l-1; i++) { el = unloaded[i]; var tmp_g = campaign.adGroups().withCondition('Name CONTAINS "__ID-' + el.id +'"').get(); if (tmp_g.hasNext()) { var adGroup = tmp_g.next(); var keywordIter = adGroup.keywords().get(); while (keywordIter.hasNext()) { var keyword = keywordIter.next(); keyword.setAdParam(1, el.p); } } else { flag_v = 0; Logger.log("  '" + el.id + "'  ."); } i_cell.getValue(); i_cell.setValue(i); flag_cell.setValue(flag_v); if (i == export_l-1) { //   if (Number(flag_v)) //     ADG date_cell.setValue(Utilities.formatDate(new Date(), "GMT+3", "dMyyyy")); i_cell.setValue(0); } } } function is_exported() { var exp_date = Number(Utilities.formatDate(new Date(date_cell.getValue()), "GMT+3", "dd")); var today = Utilities.formatDate(new Date(), "GMT+3", "dd HH").split(' '); if (Number(today[1]) < 6) return true; if ( (exp_date < Number(today[0])) || date_cell.isBlank()) return false; else return true; }
      
      







ここではまだ簡単です。 グループを取得し、キーイテレータを取得し、すべてのキーワードを調べ、すべてのキーのパラメーター1(価格)を更新しました。 できた



スクリプト5.グループのステータスを更新する



 function main() { var json_ids = JSON.parse(UrlFetchApp.fetch('http://site.ua/adwords.json').getContentText()).ids; var tmp = AdWordsApp.campaigns().withCondition('Name = ""').get(); if (tmp.hasNext()) { var campaign = tmp.next(); var tmp = campaign.adGroups().get(); } else { Logger.log('Company not found'); } while (tmp.hasNext()) { group = tmp.next(); name = group.getName(); id = /__ID-(\d+)$/.exec(name)[1]; if ( json_ids.indexOf(id) == -1 ) { group.pause(); } } }
      
      







これは最もクールで最速のスクリプトです。 その中で、すべてのアナウンスメントグループを循環し、定期的に製品IDを引き出し、アンロード中かどうかを確認し、そうでない場合は、グループを保留にしてお金を節約します。 ロガーを含めない場合、スクリプトは20分以内に3000件のアナウンスを実行します。 はい、アップロードに、このプロセスに関係するすべてのIDの配列を含むセクションが必要であることを忘れていました。 このために別のjsonを作成し、関連する以前のスクリプトと同じものに入れることができます-味と色のために。



いくつかの興味深い点







メインソース: developers.google.com/adwords/scripts/docs/reference/index

ドックがどのようになるかをご覧ください: docs.google.com/spreadsheets/d/15_W4y3GpivCjuNRWPN8HKy27MjtUeW2NTThAAPPXdkc/edit?usp=sharing



手作業の削減と合理的な節約。 ご清聴ありがとうございました。



UPD:





All Articles