この記事でわかること
- Google広告APIは公式MCPがないため、Pythonクライアントライブラリを使って入稿を自動化します。
- カード枚数が多いカルーセル広告の繰り返し入稿では、管理画面より効率が出ます。
- 作成は停止状態、テストは1件限定、配信変更はドライラン既定など4つのガードレールを組み込みます。
生成AIによる要約
Google広告には、Claude Codeから直接つながる公式のMCPサーバーがまだありません。それでも入稿を自動化したい場合は、Pythonクライアントライブラリを介してGoogle Ads APIを叩く方法が現実的な選択肢になります。
この記事では、デマンドジェネレーションのカルーセル広告を入稿した実例をもとに、手順とスクリプトの構成を整理します。カード枚数の多いカルーセルは管理画面での登録が特に手間になるため、API入稿の効果が出やすい領域です。
なお、記事中のIDやコピーはすべて仮の値に置き換えています。
管理画面ではなくAPIを選ぶ判断
すべての入稿をAPIに寄せる必要はありません。単発のキャンペーンであれば、管理画面のほうが早く終わります。
APIが向いているのは、同じ構造を繰り返し作るケースです。今回の例では、カード7枚のカルーセルを3本、それを3つの広告グループに複製する構成でした。管理画面で登録すると、カードの見出しと画像の組み合わせを63回入力することになります。
もう1つの利点が再現性です。設定をコードに書いておけば、翌月の差し替えは定義ファイルの書き換えだけで済みます。誰がいつ何を入稿したのかも、コードとログに残ります。
前提として用意するもの
必要なのは3点です。
- Pythonの
google-adsライブラリ(記事執筆時点では31.2.0で動作を確認) - 認証情報を書いた
google-ads.yaml(デベロッパートークン、クライアントID、クライアントシークレット、リフレッシュトークン、ログイン顧客ID) - 入稿する画像(カルーセルは1:1・1,080×1,080px以上)
google-ads.yaml は GoogleAdsClient.load_from_storage() で読み込みます。
from google.ads.googleads.client import GoogleAdsClient
client = GoogleAdsClient.load_from_storage("~/path/to/google-ads.yaml")
入稿の全体像
デマンドジェネレーションのカルーセル広告は、次の順序で組み立てます。単一のスクリプトにまとめず、ステップごとにファイルを分けるのが今回の構成です。
ステップを分ける理由は3つあります。エラーが起きた箇所を特定しやすいこと、途中まで成功した状態から再開できること、そして配信が始まる操作を独立したファイルに隔離できることです。
定義と処理を分離する
広告グループ名、コピー、カード構成、画像パスは共通の設定ファイルにまとめます。各ステップのスクリプトはここを読むだけにしておくと、次回の入稿は設定ファイルの書き換えで済みます。
# ads_config.py
CUSTOMER_ID = "1234567890"
EXPECTED_ACCOUNT = "取引先名" # 実行前の照合用
CAMPAIGN_ID = 1111111111
FINAL_URL = "https://example.com/"
BUSINESS_NAME = "サービス名"
HEADLINE = "見出しテキスト"
DESCRIPTION = "説明テキスト"
CTA_TEXT = "サイトを見る"
ADS = [
("広告A_カルーセル", [
("img/product_a.png", "商品Aの見出し"),
("img/product_b.png", "商品Bの見出し"),
]),
]
状態ファイルで冪等にする
APIの入稿は途中で失敗します。1枚目の画像は通ったのに5枚目でエラーになる、といった状況は珍しくありません。
そこで、作成したリソース名をJSONファイルに追記していきます。再実行時は登録済みのものをスキップするため、同じスクリプトを何度実行しても重複が生まれません。
state = load_state()
images = state.get("images", {})
ops = []
for rel, headline in cards:
if rel in images: # 登録済みはスキップ
continue
op = client.get_type("AssetOperation")
asset = op.create
asset.name = "carousel_" + rel.replace("/", "_")
asset.type_ = client.enums.AssetTypeEnum.IMAGE
with open(rel, "rb") as f:
asset.image_asset.data = f.read()
ops.append(op)
res = asset_service.mutate_assets(customer_id=CUSTOMER_ID, operations=ops)
for (rel, _), r in zip(targets, res.results):
images[rel] = r.resource_name
state["images"] = images
save_state(state)
4つのガードレール
広告APIの操作は、間違えると費用が発生します。事故を防ぐ仕組みをスクリプト側に組み込んでおくのが前提です。
1. 作成はすべて停止状態で行う
広告グループも広告も、PAUSED を明示して作成します。作成の段階では配信が始まらないため、内容を確認してから配信を判断できます。
ag.status = client.enums.AdGroupStatusEnum.PAUSED
aga.status = client.enums.AdGroupAdStatusEnum.PAUSED
2. まず1件だけ試す
--test オプションを付けたときは、対象を1件に絞って実行します。仕様の理解が間違っていた場合、被害が1件で済みます。
TEST = "--test" in sys.argv
if TEST:
targets = targets[:1]
3. 配信状態を変える操作はドライランを既定にする
有効化と停止のスクリプトだけは、引数なしで実行すると対象を表示して終了します。実際に変更するには --yes を明示します。
def confirm(argv, summary_lines):
print("対象:")
for line in summary_lines:
print(" " + line)
if "--yes" not in argv:
print("\nドライランです。実行するには --yes を付けて再実行してください。")
raise SystemExit(0)
4. 接続先アカウントを毎回照合する
複数アカウントを扱う場合、設定ファイルの顧客IDを取り違える事故が起こり得ます。実行の冒頭でアカウント名を取得し、想定と違えばその場で止めます。
def assert_account(client):
svc = client.get_service("GoogleAdsService")
q = "SELECT customer.id, customer.descriptive_name FROM customer"
for b in svc.search_stream(customer_id=CUSTOMER_ID, query=q):
for r in b.results:
name = r.customer.descriptive_name
if EXPECTED_ACCOUNT not in name:
raise SystemExit(f"中止: 想定と違うアカウントです({name})")
print(f"接続先: {r.customer.id} / {name}")
return name
raise SystemExit("中止: アカウント情報を取得できませんでした")
あわせて、停止専用のスクリプトを最初から用意しておきます。誤って配信を始めた場合の復旧手段が、同じ仕組みの中にある状態にしておくためです。広告だけ止めて広告グループには触らないオプションも用意しておくと、切り分けがしやすくなります。
入稿後は必ずクエリで検証する
作成が成功しても、意図した内容になっているとは限りません。GAQLで広告の中身と審査状況を取得し、目視で確認します。
SELECT ad_group.name, ad_group.status,
ad_group_ad.ad.name, ad_group_ad.status,
ad_group_ad.policy_summary.approval_status,
ad_group_ad.policy_summary.review_status,
ad_group_ad.ad.final_urls,
ad_group_ad.ad.demand_gen_carousel_ad.business_name,
ad_group_ad.ad.demand_gen_carousel_ad.headline,
ad_group_ad.ad.demand_gen_carousel_ad.carousel_cards
FROM ad_group_ad
WHERE ad_group.id IN (...) AND ad_group_ad.status != 'REMOVED'
カード枚数、遷移先URL、CTAの文言、オーディエンスの添付状況を確認してから有効化に進みます。
実際にはまった仕様
デマンドジェネレーションのカルーセル広告で遭遇した仕様を挙げます。いずれも2026年8月時点の挙動です。
| 事象 | 内容 |
|---|---|
| オーディエンスは1つまで | 新規作成した広告グループには、オーディエンスリソースを1つしか添付できない。2つ目は Audience segment attachment is not allowed when use audience grouped bit is set to true で拒否される |
| カードには遷移先URLが必須 | カードアセット側に final_urls を設定しないと作成できない。画像は1:1の square_marketing_image_asset だけでよく、横長版は不要 |
| ショート面には配信されない | カルーセルはYouTubeショートとインストリームの配信対象外。ショート向けに作った広告グループに入れても配信されない |
| 審査は作成時点で始まる | 停止状態で作成しても審査は進む。有効化を待つ必要はない |
| field_maskの取得方法 | 更新時のマスクは client.get_type("FieldMask") では取れない。google.api_core.protobuf_helpers.field_mask(None, op.update._pb) を使う |
Claude Codeに任せる範囲
スクリプトの作成そのものはClaude Codeに任せられます。APIのバージョン差でフィールド名が変わりやすい領域のため、エラーメッセージを渡して修正させる進め方が効率的でした。
一方で、判断が必要な部分は手元に残します。どのオーディエンスに当てるか、コピーをどうするか、いつ配信を始めるかは運用者の領域です。
指示の出し方としては、「停止状態で作る」「1件だけ試す」「配信を変える操作は確認を挟む」といった制約を最初に伝えておくと、生成されるスクリプトの安全性が上がります。
まとめ
- Google広告に公式MCPは無いため、Pythonクライアントライブラリ経由でAPIを叩く
- 単発なら管理画面が早い。同じ構造を繰り返す入稿でAPIの効果が出る
- ステップごとにスクリプトを分け、状態ファイルで冪等にすると再実行が安全になる
- 作成は停止状態、まず1件、配信変更はドライラン既定、実行前にアカウント照合の4点を組み込む
- 停止用スクリプトを最初から用意し、いつでも戻せる状態にしておく
まず試すべき1アクション:既存アカウントに対して読み取りだけのクエリを1本実行してください。SELECT customer.id, customer.descriptive_name FROM customer が通れば、認証設定は完了しています。書き込みはその後で構いません。
関連記事
この記事をシェア
参照元
ryottaman
広告代理店で17年、現在は事業会社でインハウスマーケティングを担当しています。
SIGNALZの記事はAIを活用して作成し、10年以上の運用型広告の実務経験をもとに内容を確認・監修しています。制作方針の詳細はサイトについてをご覧ください。
Google検索の優先ソースにSIGNALZを追加
追加すると、Google検索のトップニュースでSIGNALZの記事が見つけやすくなります。AIモードとAIによる概要でも「優先」バッジが付きます。設定はいつでも解除できます。