Yahoo広告APIのレポートをPythonで取る4手順

Yahoo広告のレポートをPythonで取ろうとして、最初の1本が動くまでに半日が溶けた。原因はコードの書き方ではない。Google広告やMeta広告と違い、Yahoo検索広告APIのレポートは「その場で数値が返るAPI」ではないからだ。定義を登録し、ジョブの完了を待ち、CSVをダウンロードし、後片付けをする。この4手順を知らずにレスポンスをJSONとして読もうとすると、出てくる例外の文面からは原因がまったく読み取れない。ここでは当月消化を毎日取得している実運用コードをもとに、4手順の流れとつまずいた箇所を書く。対象はYahoo検索広告API v19だ。

レポート取得は「4手順のジョブ処理」になる

Yahoo検索広告APIのレポートは、1回のリクエストで数値が返らない。実際の流れは次の4手順だ。

  • (1) ReportDefinitionService/add でレポート定義を登録し、reportJobId を受け取る
  • (2) ReportDefinitionService/get を叩き、reportJobStatus が COMPLETED になるまで待つ
  • (3) ReportDefinitionService/download でCSVを受け取る
  • (4) 不要になった定義を remove で片づける

実測では、(2)の完了まで3秒から15秒かかった。運用コードでは3秒間隔で最大40回ポーリングしている。日次バッチなら十分な余裕だ。エンドポイントは ads-search.yahooapis.jp/api/v19 になる。ドメインを ads.yahoo.co.jp と書くと404が返る。旧バージョンのv16やv17を叩くと code:0004 URL not found だ。

もう1つ、最初に必ず詰まるのがヘッダーである。リクエストには MCC のIDを x-z-base-account-id ヘッダーに入れる必要がある。これを付け忘れると code:0001 Invalid Request が返る。さらに厄介なのは、レポート以外の読み取り系APIだとエラーにならず0件で返ってくることだ。「キャンペーンが1本もない」と読み違えた。仕様の詳細はLINEヤフー広告の公式リファレンスにある。Yahoo広告API全般のつまずきどころはYahoo広告APIをPythonで自動化して詰まった5つの罠にまとめてある。

罠1: bodyとfieldsは「通る最小構成」から始める

add に渡すbodyに余計なフィールドを入れると、code:0005 requestKey=format requestValue=null のようなエラーが返る。この文面を素直に読むと「formatの値がnullだから埋めろ」と解釈してしまう。実際の意味は逆だ。そのフィールドをAPIが知らない、つまり消せという意味である。

しかもこのエラーは先頭の1つしか返さない。余計なフィールドが5個あれば、5回往復して1個ずつ削ることになる。最小構成で通してから足すほうが速い。

v19で通った最小のbodyは accountId / reportName / reportType / reportDateRangeType / dateRange / fields の6つだけだ。逆に、他媒体の感覚で入れたくなる format・encode・isTemplate・intervalType・dateRangeType・reportLanguage・reportSkipReportSummary・reportCompressType・reportIncludeDeleted は、すべて書かない。reportName は同名だと衝突するので、末尾にUNIX時刻を付けてユニークにしている。

v19に無いフィールドはTypeErrorになって返る

fields の指定にも落とし穴がある。KEYWORDS レポートで AD_GROUP_NAME・MATCH_TYPE・AVG_CPC を指定すると V0001 が返る。これらはv19に存在しないためだ。

問題はエラーの出方にある。addのレスポンス自体は200で返り、中の reportDefinition が null になる。そのため reportJobId を取り出す行で TypeError が出る。エラーの発生行と本当の原因が離れているので、デバッガでレスポンスの中身をそのまま表示するまで気づけなかった。

実際に使えたのは CAMPAIGN_NAME / KEYWORD / COST / CLICKS / IMPS / CONVERSIONS だ。平均CPCのフィールドは無いので、COST を CLICKS で割って自分で出す。この割り算をレポート側でなくPython側に置いたほうが、クリック0除算の扱いを自分で決められて都合がよかった。

回避策は単純で、add のレスポンスを変数に入れたら、reportJobId を取りに行く前に errors の有無を必ず判定する。1行増やすだけで、原因不明のTypeErrorが「どのフィールドが悪いか」まで書かれたエラーメッセージに変わる。

罠2: downloadはJSONではなくCSVを返す

最後の罠がいちばん時間を取られた。ReportDefinitionService/download のレスポンスはCSVのプレーンテキストである。他のサービスと同じ共通関数で叩くと、内部で resp.json() が走って Expecting value: line 1 column 1 (char 0) になる。認証まわりを疑って1時間浪費した。

対処は、download だけ共通のpost関数を経由させず、requests.post に認証ヘッダーを自分で組んで渡し、resp.text を読むことだ。なお ReportService/download というパスは存在しない。404が返る。正しいのは ReportDefinitionService 側である。

CSVを読むときにもう1つ注意がいる。ヘッダー行が日本語で返ってくる。1列目が「キャンペーン名」、2列目が「コスト」だ。英語のフィールド名でカラムを引き当てる実装にすると、指定は英語なのに戻りは日本語なので全部外れる。列名でなく順序で読むか、日本語のヘッダーで照合するかを最初に決めておく。

消化額がちょうど2倍になった原因と検算の手順

実装が通ったあと、集計した当月消化が管理画面の値のちょうど2倍になった。原因はCSVの最終行が合計行だったことだ。この行はキャンペーン名の列が空欄で返る。全行をループして足すと、明細と合計を二重に足すので必ず2倍になる。

「ちょうど2倍」は幸運な壊れ方だった。危ないのは、日次バッチに載せてから誰も突き合わせなくなることだ。本番に載せる前に、API合計と管理画面の当月消化を1回だけ手で照合する工程を入れている。3媒体をまとめて扱う場合の統合の考え方は広告3媒体レポート統合をPythonで実装した手順に書いた。

この手順の完全版はnoteの実践ガイドにまとめている。

コピペで使えるYahooレポート実装チェックリスト

ここまでの内容を、着手前に上から確認できる形にした。ブックマークして、自分の環境に合わせて書き換えて使ってほしい。

  • (1) エンドポイントは ads-search.yahooapis.jp/api/v19 か。旧バージョンを叩いていないか
  • (2) 全リクエストに x-z-base-account-id(MCCのID)を付けているか
  • (3) add の body は accountId / reportName / reportType / reportDateRangeType / dateRange / fields の6つだけか
  • (4) reportName に時刻を足してユニークにしているか
  • (5) fields は CAMPAIGN_NAME / KEYWORD / COST / CLICKS / IMPS / CONVERSIONS の範囲に収まっているか
  • (6) add の直後に errors を判定してから reportJobId を取り出しているか
  • (7) get のポーリングは3秒間隔・上限回数つきで、タイムアウト時に例外を投げているか
  • (8) download だけは resp.text で受けているか。json() を通していないか
  • (9) CSVは1行目のヘッダーと、キャンペーン名が空の最終行を捨てているか
  • (10) 本番に載せる前に、API合計と管理画面の当月消化を1回突き合わせたか

(3)(6)(8)(9)の4つが、今回半日を溶かした箇所そのものだ。ここだけ先に潰せば、初回の実装は1時間ほどで通る。

[PR] 取得した数値をそのままクライアント向けの報告資料にするなら、スライド生成を自動化するツールも併用できる: AIスライド作成ツール「イルシル」を試してみる

まとめ

Yahoo検索広告APIのレポートでつまずく原因は、ほぼ3つに集約される。エラー文面の意味が直感と逆であること、v19に無いフィールドが別の例外になって返ること、downloadだけCSVであることだ。この3つを先に知っていれば、実装そのものは難しくない。まずはCAMPAIGN_NAMEとCOSTの2フィールドだけで1本通し、管理画面の数値と突き合わせるところから始めるのが確実だ。そこが合えば、あとはfieldsを足していくだけで済む。

実務でそのまま使いたい人へ

本記事の手法の完全版(実際のコード・テンプレート・つまずき対処つき)は、運営者のnote(note.com/ryo_ai_hack)で公開している。実データに基づく実践ガイドをまとめて読める。

DMM 生成AI CAMP

コメント

このブログの人気の投稿

Claude Skills販売で月5万稼ぐ3ステップ実践

Claude CodeでExcel自動化副業を月5万にする手順

Yahoo広告APIをPythonで自動化して詰まった5つの罠