【PHP】Google Ads APIをサンプルプログラム無しで使いたい！！

#はじめに

**Google Ads API**は、Google広告の最新のプログラマティック インターフェースである。
概要は[こちら](https://developers.google.com/google-ads/api/docs/start?hl=ja)

前身はGoogleの広告サービス＝AdWordsのAPI（Adwords API）で、
2018年にAdWordsを「Google広告」に改称したことに伴い、
新APIとして登場した。らしい。いつの間に・・・

改称した詳しい経緯は[こちら](https://unyoo.jp/2018/07/google-marketing-live-2018/)

最新ニュースなどを全然チェックしていなかったので
いきなり「AdwordsAPIが使えなくなる」って情報を見て「うそお！？」とググったら
AdwordsAPIのサイトから日本語版が消えてた・・・あからさまだよ、Googleさん。。

当方、現在AdwordsAPIを使用してレポートデータを取得したシステムを構築している。
今後AdwordsAPIがいつ使えなくなるか分からないので、大急ぎで引越し準備を始めた。

Google Ads APIに関しては、[ドキュメント](https://developers.google.com/google-ads/api/docs/reporting/example?hl=ja)がしっかり準備されているせいか、
検索しても情報が極端に少なかった。
何度も心折れながら試行錯誤した成果を、ここに記録しておくことにする。

~~ちなみにGoogle Ads APIは2020年3月現在β版。~~
~~正式版はいつリリースされるのよ。。。~~

<font color="Red">
<<2020/10/22 ADD>>
2020/09/21に正式版がリリースされたようです。
詳しいアナウンスは[こちら](https://ads-developers.googleblog.com/2020/09/announcing-google-ads-api-is-out-of-beta.html)
本記事の内容は正式版でも使えることを確認済みです。
リリース時のバージョンはv5。
</font>

#前提

・AdwordsAPIを既に利用している場合、認証情報はGoogleAdsAPIに引き継がれるため
　設定情報を変更する必要はない。
　⇒ただし、そのまま使えるわけではなく、新たにGoogleAdsAPIを利用するためには
　　Google広告の「ツールと設定」⇒「APIセンター」で、規約に同意する必要がある

・AdwordsAPIもAdsAPIも、サンプルプログラム（「**クライアントライブラリ**」）が用意されている。
　Java/.NET/PHP/Python/Ruby/Perlと幅広くカバーされている。さすが天下のGoogleさん。

・AdwordsAPIもAdsAPIも、サンプルプログラムはcomposerありきで作られている。
　**composer**については[こちら](https://getcomposer.org/)
　※ドキュメントが英語だったので翻訳機能使ったら
　　「composer」が「作曲家」と変換されて「OH…ナニソレ」と心が折れた昼下がり

・当方、事情があってcomposerをインストールできない環境。
　何とかサンプルを使用せずに直接APIを叩きたい。

**★注意！！★**
公式はあくまで
**「クライアントライブラリを使用してリクエストを送信することを強くおすすめします」**
と言っているので、
もしここのやり方はあくまでも参考って認識で。。。

#データ取得：oAuth2認証

最初にリフレッシュトークンとクライアントID、クライアントシークレットを使ってoAuth2認証を行う。
認証に成功するとアクセストークンが取得できる。

```
//認証用URL
$oAuth2_url = "https://oauth2.googleapis.com/token";

//リフレッシュトークン
$refresh_token = "REFRESH_TOKEN";

//クライアントID
$client_id = "CLIENT_ID";

//クライアントシークレット
$client_secret = "CLIENT_SECRET";


//curl START
$curl = curl_init();

//OPTIONをセット
curl_setopt_array($curl, [
    CURLOPT_URL => $oAuth2_url,
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_POSTFIELDS => http_build_query([
        "refresh_token" => $refresh_token,
        "client_id" => $client_id,
        "client_secret" => $client_secret,
        "grant_type" => "refresh_token",
    ]),
]);

//curl EXEC(文字列で取得)
$resp =  curl_exec($curl);

//エラーハンドリング用
$_errno = curl_errno($curl);

//curl END
curl_close($curl);

//エラーハンドリング
if ($_errno !== CURLE_OK) {
    //エラー処理
}

//エラーでなければjsonを連想配列化        
$jsonresp = json_decode($resp, true);

//アクセストークンを取得
$access_token = $jsonresp["access_token"];
```

#データ取得：レポートデータ取得

アクセストークンを取得できたら、いよいよ肝心のレポートデータを取得する。

oAuth2認証で取得したアクセストークンと、
API取得時に付与されるディベロッパートークン、MCCのログインカスタマーIDをヘッダーにセットする。

※ログインカスタマーIDは、Google広告の右上のアカウント名上に表示されている番号のこと。

```
//ディベロッパートークン
$developer_token = "DEVELOPER_TOKEN";

//ログインカスタマーID
$login_customer_id = "LOGIN_CUSTOMER_ID";	//XXX-XXX-XXXX形式なのでハイフンなし10桁で！


//ヘッダー情報をセット
$header = [
    "Content-Type: application/json", 
    "Accept: application/json",
    "Authorization: Bearer ".$access_token, 
    "developer-token: ".$developer_token,
    "login-customer-id: ".$login_customer_id,
];
```

次に、必要なレポートデータを設定する。

レポートを取るためのエンドポイントはhttps://googleads.googleapis.comで、
これにさらにバージョン、処理によって違う値を付与する。

今回はレポートデータ取得なので、**googleAds:search**というリソースを使用する。

```

$url = "https://googleads.googleapis.com/{v1}/customers/{CLIENT_ID}/googleAds:search";
```

※{CLIENT_ID}にはデータ取得したいクライアントID（MCCのでも違うものでもOK）をセットする。
※{v1}には使用するAPIのバージョンを指定。v1ならバージョン１。
※クライアントIDはlogin-customer-idと同じくXXX-XXX-XXXX形式のもの。ハイフンなし10桁。

AdwordsAPIと同じくGoogleAdsAPIは**クエリ言語**でデータ取得ができる。
ただし新仕様はわかりやすいようで非常に！分かりにくい。
ドキュメントを一生懸命解読しないと理解できない・・・。

今回は広告グループのレポートデータを取得するクエリ言語を例として示す。
個人的にはこういう情報が欲しかったのよ。。

```
/**
*  GoogleAdsに渡すクエリ言語の項目[SELECT]
*/
private static $SELECT = [
	 "ad_group.resource_name"
	 ,"ad_group.id"
	 ,"ad_group.name"
	 ,"ad_group.status"
	 ,"ad_group.campaign"
	 ,"ad_group.type"
	 ,"ad_group.cpc_bid_micros"
	 ,"ad_group.cpm_bid_micros"
	 ,"ad_group.cpv_bid_micros"
	 ,"ad_group.base_ad_group"
	 ,"ad_group.target_cpa_micros"
	 ,"ad_group.effective_target_cpa_micros"
	 ,"ad_group.effective_target_cpa_source"	//adgroup

	//以下のsegments/campaign/metricsは、どのフィールドからも参照できる項目ぽい。

	 ,"segments.date"

	 ,"campaign.id"

	 ,"metrics.all_conversions"
	 ,"metrics.average_cost"
	 ,"metrics.average_cpc"
	 ,"metrics.average_cpm"
	 ,"metrics.clicks"
	 ,"metrics.conversions"
	 ,"metrics.cost_micros"
	 ,"metrics.cost_per_conversion"
	 ,"metrics.cross_device_conversions"
	 ,"metrics.ctr"
	 ,"metrics.engagements"
	 ,"metrics.impressions"
	 ,"metrics.phone_impressions"
	 ,"metrics.search_impression_share"
	 ,"metrics.value_per_all_conversions"
	 ,"metrics.all_conversions_value"
	 ,"metrics.conversions_from_interactions_rate"
	 ,"metrics.conversions_value"
	 ,"metrics.search_absolute_top_impression_share"
	 ,"metrics.gmail_forwards"
	 ,"metrics.gmail_saves"
	 ,"metrics.gmail_secondary_clicks"
	 ,"metrics.search_top_impression_share"
	 ,"metrics.top_impression_percentage"
	 ,"metrics.absolute_top_impression_percentage"
	 ,"metrics.current_model_attributed_conversions"
	 ,"metrics.current_model_attributed_conversions_value"
 
];

/**
*  GoogleAdsに渡すクエリ言語のフィールド[FROM]
*/
const FROM = "ad_group";

/**
*  GoogleAdsに渡すクエリ言語のWHERE条件：期間
*  今日とか昨日とか１ヶ月とか指定はいろいろできる。
*/
const WHERE_PERIOD = "segments.date BETWEEN 'YYYYMMDD' AND 'YYYYMMDD'";

/**
*  GoogleAdsに渡すクエリ言語のWHERE条件：キャンペーンID
*  ※これGoogle広告の画面上は見えないので探すの大変
*/
const WHERE_CAMPID = "campaign.id = 'XXXXXXXX'";

//クエリをセット：SQL文みたいな形式
$_query_str = "SELECT ".implode(",", self::$SELECT)." FROM ".self::FROM." WHERE ".self::WHERE_PERIOD." AND ".self::WHERE_CAMPID;

//GoogleAdsに渡すために配列化（実際にはjsonで渡す）
$query = ["query" => $_query_str];
```


クエリをセットしたら、いよいよレポートデータを要求！

```
//curl START
$curl = curl_init();

//OPTIONをセット
curl_setopt_array($curl, [
    CURLOPT_URL => $url,
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 120,
    CURLOPT_HTTPHEADER => $header,
    CURLOPT_POSTFIELDS => json_encode($query),	//ここにクエリをセット
]);

//curl EXEC(文字列で取得)
$resp = curl_exec($curl);

//エラーハンドリング用
$_errno = curl_errno($curl);

	//curl END
curl_close($curl);

//エラーハンドリング
if ($_errno !== CURLE_OK) {
    //エラー処理
}

//エラーでなければjsonを連想配列化        
$result = json_decode($resp, true); 

//取得されたデータはフィールドごとに格納されている
for ($i = 0; $i < count($result); $i++) {
    $_line = $result[$i];   //一行データ
    if (!is_array($_line)) continue;

    //日付：フィールドsegmentsのデータ
    $_date = $_line["segments"]["date"];

    //キャンペーンID：フィールドcampaignのデータ
    $_campid = $_line["campaign"]["id"];

    //広告グループID：フィールドadGroupのデータ
    $_adgroupid = $_line["adGroup"]["id"];
    //キャンペーン名
    $_campname = $_line["adGroup"]["name"];

    //表示回数：フィールドmetricsのデータ
    $_viewcnt = $_line["metrics"]["impressions"];
}
```

取れた！取れたよー！！

#おまけ：キャンペーンIDと広告IDを取得する
キャンペーンIDや広告グループIDをいちいち確認するのめんどいから、
あらかじめ全広告グループの取得するプログラムも作った。

キャンペーン・広告グループそれぞれでステータスを持っているので、
必要ならステータスを条件に加えて取ってくると便利！
ステータスは[ENABLED][PAUSED][REMOVED]。
※ちなみにYahooAPIのステータスは[ACTIVE][PAUSED]なので、
　GoogleとYahoo両方使ってる人は間違えないように注意すること。
※広告グループステータスOFFでもキャンペーンステータスONだけの条件だと
　表示されてしまうので、両方をしっかり条件に入れること。

```
    /**
     *  GoogleAdsに渡すクエリ言語のSELECT項目を配列で指定
     */
    private static $SELECT = [
         "campaign.id"
        ,"campaign.name"
        ,"campaign.status"
        ,"ad_group.id"
        ,"ad_group.name"
        ,"ad_group.status"
    ];

    /**
     *  GoogleAdsに渡すクエリ言語のFROM項目[固定]
     */
    const FROM = "ad_group";


    //クエリをセット
    $_query_str  = "SELECT ".implode(",", self::$SELECT)." FROM ".self::FROM;
    $_query_str .= ad_group.status IN ('ENABLED', 'PAUSED');
    $_query = ["query" => $_query_str];

```





Googleさんの壁は厚く、oAuth2認証のためにドアを何度も何度も叩いてもスルーされまくり、
ようやく開けてくれたと思ったら不親切なエラーメッセージばっかり返ってきたりと
ショボーンと心折れて帰宅した日々が続いたもので、取れたときは嬉しくて仕事中だったけど叫んだな。。。

何度も言いますが、あくまでもGoogleAdsAPIはサンプルプログラムを利用したリクエストがベスト（推奨）です。

ただ、同じように苦しんでいる人の参考に少しでもなればいいと思います。

健闘をいのる！！！


おしまい。