第 13 章
Google Ads 脚本与自动化
自动化是规模化管理的核心能力。本章脚本需经测试后用于生产环境。
★ 与 Premier Partner 的关系
规模化运营需要自动化。Premier Partner 代理需要管理大量账户,手工操作不可持续。
13.1 入门:30 分钟部署你的第一个脚本#
进入 Google Ads → 工具 → 批量操作 → 脚本 → + 新建脚本。编辑器支持 JavaScript ES5。以下是一个最简单的脚本——每天邮件报告:
function main() {
var report = AdsApp.report(
"SELECT campaign.name, metrics.impressions, metrics.clicks, metrics.cost_micros, metrics.conversions " +
"FROM campaign WHERE segments.date DURING YESTERDAY");
var rows = report.rows();
var output = "Campaign\tImpressions\tClicks\tCost\tConversions\n";
while(rows.hasNext()) {
var row = rows.next();
output += row["campaign.name"] + "\t" +
row["metrics.impressions"] + "\t" +
row["metrics.clicks"] + "\t" +
(row["metrics.cost_micros"] / 1000000).toFixed(2) + "\t" +
row["metrics.conversions"] + "\n";
}
MailApp.sendEmail("your@email.com", "Daily Report", output);
}
设置执行频率:每天 → 保存 → 预览 → 运行。
13.2 5 个直接可用的脚本#
脚本 1:暂停 7 天无转化的关键词
function main() {
var campaignIterator = AdsApp.campaigns().get();
while(campaignIterator.hasNext()) {
var campaign = campaignIterator.next();
var keywordIterator = campaign.keywords()
.withCondition("ad_group.status = ENABLED")
.withCondition("keyword.status = ENABLED")
.get();
while(keywordIterator.hasNext()) {
var keyword = keywordIterator.next();
var stats = keyword.getStatsFor("LAST_7_DAYS");
// getCost() 返回账户币种金额(非 micros)
if(stats.getConversions() == 0 && stats.getCost() > 50) {
keyword.pause();
Logger.log("Paused: " + keyword.getText() + " - Cost: $" + stats.getCost().toFixed(2));
}
}
}
}
单位说明
Google Ads Scripts 中 Stats.getCost() 和 Budget.getAmount() 直接返回账户币种金额(如 USD 10.50)。不要除以 1,000,000——那是 Google Ads API(GAQL)的 micros 单位。脚本与 API 的单位不同。
脚本 2:建议新搜索词(安全模式:写入 Sheet 供人工审批)
function main() {
var sheet = SpreadsheetApp.openById("YOUR_SHEET_ID").getActiveSheet();
sheet.appendRow(["Date", "Search Term", "Clicks", "Conversions", "Cost"]);
var report = AdsApp.report(
"SELECT search_term.view_text, metrics.clicks, metrics.conversions, metrics.cost_micros " +
"FROM search_term_view WHERE segments.date DURING LAST_30_DAYS " +
"AND metrics.conversions > 0 AND metrics.clicks > 10 " +
"AND search_term.view_text NOT LIKE '%.%'");
var rows = report.rows();
while(rows.hasNext()) {
var row = rows.next();
var term = row["search_term.view_text"];
// 检查是否已存在(全局去重)
var exists = AdsApp.keywords()
.withCondition("keyword.text = '" + term.replace(/'/g, "\\'") + "'")
.get().hasNext();
if(!exists) {
sheet.appendRow([
new Date(),
term,
row["metrics.clicks"],
row["metrics.conversions"],
(row["metrics.cost_micros"] / 1000000).toFixed(2)
]);
}
}
}
安全提醒
自动将搜索词添加为关键词可能带来无关流量和预算风险。务必写入 Google Sheets 经人工审核后再添加。本例中 report 使用 cost_micros(API 单位),而 Scripts 的对象方法如 getCost() 直接返回币种金额——注意区分。
脚本 3:预算超限自动告警(Slack)
var SLACK_WEBHOOK = "https://hooks.slack.com/services/YOUR/WEBHOOK/URL";
var BUDGET_THRESHOLD = 0.8; // 告警阈值:已用预算的 80%
function main() {
var campaigns = AdsApp.campaigns().withCondition("campaign.status = ENABLED").get();
while(campaigns.hasNext()) {
var c = campaigns.next();
var budget = c.getBudget();
var stats = c.getStatsFor("LAST_7_DAYS");
// Scripts 中 getCost() / getAmount() 直接返回币种金额
var spend = stats.getCost();
var dailyBudget = budget.getAmount();
var totalBudget = dailyBudget * 7;
if(totalBudget > 0) {
var spendRate = spend / totalBudget;
if(spendRate > BUDGET_THRESHOLD) {
var msg = "⚠ Campaign \"" + c.getName() + "\" spent " + (spendRate*100).toFixed(0) +
"% of weekly budget ($" + spend.toFixed(2) + " / $" + totalBudget.toFixed(2) + ")";
UrlFetchApp.fetch(SLACK_WEBHOOK, {method:"POST", payload:JSON.stringify({text:msg}), contentType:"application/json"});
}
}
}
}
脚本 4:质量分监控→Sheets
function main() {
var sheet = SpreadsheetApp.openById("YOUR_SHEET_ID").getActiveSheet();
sheet.appendRow(["Date", "Campaign", "Keyword", "Quality Score", "Impressions", "Clicks"]);
var report = AdsApp.report(
"SELECT campaign.name, keyword.text, metrics.quality_score, " +
"metrics.impressions, metrics.clicks " +
"FROM keyword WHERE metrics.quality_score < 5 AND metrics.impressions > 100 " +
"AND segments.date DURING LAST_7_DAYS");
var rows = report.rows();
while(rows.hasNext()) {
var row = rows.next();
sheet.appendRow([new Date(),
row["campaign.name"], row["keyword.text"],
row["metrics.quality_score"],
row["metrics.impressions"], row["metrics.clicks"]]);
}
}
脚本 5:MCC 跨账户预算汇总
function main() {
var sheet = SpreadsheetApp.openById("YOUR_SHEET_ID").getActiveSheet();
sheet.appendRow(["Account Name", "Customer ID", "Cost", "Conversions", "Impressions", "Clicks"]);
var accounts = AdsManagerApp.accounts().get();
while(accounts.hasNext()) {
var account = accounts.next();
AdsManagerApp.select(account);
var stats = AdsApp.currentAccount().getStatsFor("LAST_7_DAYS");
// Scripts 中 getCost() 直接返回币种金额(非 micros)
sheet.appendRow([
account.getName(),
account.getCustomerId(),
stats.getCost().toFixed(2),
stats.getConversions(),
stats.getImpressions(),
stats.getClicks()
]);
}
}
13.3 常用 API 端点速查#
| 功能 | API 端点 | GAQL 查询示例 |
|---|---|---|
| 数据查询 | GoogleAdsService.SearchStream | SELECT campaign.name, metrics.impressions FROM campaign |
| 广告系列操作 | CampaignService.MutateCampaigns | operations: [{update: {resource_name, status: PAUSED}}] |
| 离线转化上传 | ConversionUploadService.UploadClickConversions | conversions: [{gclid, conversionValue, conversionDateTime}] |
| 报表导出 | GoogleAdsService.Search | 配合 pagination 分页导出大量数据 |
13.4 脚本与 API 工程化治理#
生产环境使用自动化必须遵循以下原则:
代码部署规范
- Preview 模式:所有脚本第一次运行时必须使用 Preview 模式,确认输出符合预期后再切换为正式运行
- 白名单策略:涉及"暂停/启用/修改预算/新增对象"的操作,必须先用 Logger.log 输出结果,人工确认后再放开执行
- 幂等设计:脚本多次运行应产生相同结果(或只执行一次、第二次无副作用)
- 日志记录:每个脚本在 Logger.log 中输出关键操作的时间和影响范围
- 异常告警:脚本应包含 try-catch 块,出错时通过 MailApp.sendEmail 或 Slack 告警
API 工程化
- Developer Token:生产环境申请 standard token(而非 test token),注意配额限制
- OAuth 2.0:管理已归集到自有 MCC 的账户时可使用 Service Account;替其他用户提供授权接入的 SaaS 应使用 multi-user authentication。两种方式都需要 developer token
- 分页与重试:大数据量查询必须分页,遇到 quota error 使用指数退避重试
- Partial Failure:批量操作开启 partial failure 模式,避免单条失败导致全部回滚
- 版本管理:API 每年更新版本,提前 6 个月关注废弃公告
上线审批与回滚
| 阶段 | 要求 | 交付物 |
|---|---|---|
| 开发 | 只读查询或 Logger.log,不执行 mutate | 影响对象样例、阈值说明 |
| Preview | 用测试账户和小范围白名单验证 | 运行日志、误报清单 |
| 审批 | 负责人确认影响范围、预算上限、回滚方式 | 审批记录、版本号 |
| 生产 | 先告警后执行,逐步扩大账户范围 | 变更日志、失败告警 |
| 回滚 | 禁用定时任务,按日志恢复原状态 | 回滚记录、复盘结论 |
密钥不得写入脚本正文或共享表格。使用受限权限的密钥存储,并记录轮换日期。每次 API 请求保留 request ID,便于定位失败调用。
Google Ads Editor
- 批量编辑的首选工具,支持离线操作和变更草稿
- 适用于:批量添加/修改关键词、广告文案、出价调整
- 不适用于:基于实时数据的决策(需使用脚本或 API)
- 变更前导出原账户为备份文件,变更后可回滚
Automated Rules
- 适用场景:定时暂停、预算调整、标签管理、邮件告警
- 推荐用于简单条件规则(如"CPA > $50 时暂停关键词")
- 复杂逻辑(跨账户/多条件组合/自定义计算)应使用脚本
自动化边界
默认原则:先告警、后执行。涉及预算变更、广告暂停、关键词新增的操作必须先进入人工审批流程。只有数据监控和报告类的自动化可以全自动运行。
✦ ✦ ✦
本章要点
- Google Ads Scripts 基于 JavaScript,免费,在后台运行
- 5 个可直接部署的脚本覆盖大部分日常需求
- API 用于更复杂的集成需求
- 自动化监控 + 人工决策是最佳组合
✓ 行动清单
- 部署"暂停 7 天无转化关键词"脚本
- 部署"质量分监控"脚本写入 Google Sheets
- 创建 MCC 级别脚本管理所有账户
- 为每个自动化任务补齐 Preview、审批、日志、告警和回滚记录