ZOZOTOWNなどのファッション通販サイトの人気アイテムランキングデータを集計して、ファッションブランドの人気度をグラフ化したり、集計値でブランドランキングをしている「TrendinG(トレンディング)」というサイトを1年前頃からやっていました。

ファッション&ブランドの情報サイトとなれば、ブランド関連のInstagram投稿画像の表示もできたら良さそうとは思っていたものの、InstagramのAPIをこれまで触ったこともなく、しかも、Instagram APIの提供元があのFacebook(今はMetaですね)で、かなりクセがありそうな気もしていたこともあり、今までやらずにおりました。

そんなとき、先日ふとこのサイトのドメインパワーを見てみたところ、結構良い数値が出ているのに気が付きました。

サブドメインサイトTrendinGのドメインパワー

サイト自体はcronを使って半自動で動いていますが、このまま単に動かし続けてるのも少々もったいない気がしてきたので、少し手入れをしてみることを思いたち、やりたいと思っていたInstagram APIを使ったハッシュタグ検索&投稿データ収集をやってみることにしました。

そこで、この記事では「Meta for Developers」へのマイアプリ登録や、InstagramグラフAPIのアクセストークン取得やInstagramビジネスIDの取得などをある程度分かる方を対象に、ハッシュタグ検索でタグ付けされた投稿データを取得し、サイト上に表示させた流れについて、InstagramグラフAPIのサンプルPHPコードや、APIのJSONレスポンスデータのクセなども交えつつご紹介したいと思います。

「Meta for Developers」のマイアプリ登録をしてない、もしくは、新規でサイト用のfacebook、Instagramのアカウントを作るところからやってみたい(今回私はこのパターンです)といった方は、「ゼロから始めるInstagramグラフAPI Ver12.0 2022年版」に登録までの流れをまとめてあります。

合わせて参考にしてみてください。

ハッシュタグ検索をして、投稿データを取得したい

TrendinG(トレンディング)」では、ファッションブランドを人気順にランキングで100ブランドをタイル状に表示させています。各ブランドには詳細ページが用意してあるので、そこにブランド名ハッシュタグでタグ付けされたInstagramの投稿画像を表示させたいと思います。

InstagramグラフAPIの構成を調べる

方向性が固まったので、早速「Meta for Developers」の「InstagramグラフAPI」リファレンスを見てみます。リファレンスを見ると、用意されているAPIには下記があるようです。

APIの種類APIの概要
IG ContainerInstagramグラフAPIを利用して、Instagramに画像投稿などをする際に利用する、メディアオブジェクトコンテナのステータスチェック用API。
IGコメントInstagramグラフAPIを利用して、コメントの取得、コメントへの返信、コメントの削除、コメントの非表示/表示などができるAPI。
IGハッシュタグ検索検索されたハッシュタグ(キーワード)に対応するハッシュタグIDを返すAPI。
IGハッシュタグ指定されたハッシュタグIDでタグ付けされた最新投稿や最も人気のある投稿を取得するAPI。
IGメディア指定されたメディアIDの投稿画像やキャプション、イイネ数を取得するAPI。
IGユーザー指定されたInstagramビジネスアカウント、クリエイターアカウントのユーザ名やフォロワー数を返すAPI。

他のAPIではありそうな、キーワード検索をするとすぐに関連データを返すようなAPIはなく、「IGハッシュタグ検索API」でブランド名のハッシュタグIDを一旦取得して、それを「IGハッシュタグAPI」にセットして投げてあげないと投稿された画像・動画データを取得することができないようです。さすがはFacebookのAPIという感じがしてきました。

ということで、この「IGハッシュタグ検索」「IGハッシュタグ」の2APIを使って投稿データを取りにいってみたいと思います。

InstagramグラフAPIのリファレンスページ
InstagramグラフAPIのリファレンス

ハッシュタグ検索(IG Hashtag Search)

ハッシュタグをキーワード検索するためには、下記のような形でリクエストを生成する必要がありました。

https://graph.facebook.com/v12.0/?user_id=「InstagramビジネスID」&q=「キーワード」&access_token=「アクセストークン」

「InstagramビジネスID」「アクセストークン」が確保できていれば、比較的簡単にクエリを作ることはできると思います。取得がまだの方は「ゼロから始めるInstagramグラフAPI Ver12.0 2022年版」を見てご用意ください。

リファレンスでは、「cURL」で取りにきてと書いてありますが、リクエストをそんなにいじることもなさそうなので、手っ取り早く「file_get_contents()」で取ってしまいました。

//ハッシュタグ検索(バージョン12.0です)
$APIPath = "https://graph.facebook.com/v12.0/ig_hashtag_search";

//あなたのIDとアクセストークン
$instragramID = '11111111111111111';
$ACCESS_TOKEN = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA';

//ハッシュタグ(投げたいキーワード)
$hash_word = 'キーワード';

//Request
$q = $APIPath .'?user_id=' .$instragramID .'&q=' .$hash_word .'&access_token=' .$ACCESS_TOKEN;

//JSON取得
$InstagramBuff = file_get_contents($q);

検索したキーワードに対応するハッシュタグIDがJSONで返ってくるので、これをjson_decode()すればIDは取り出せました。

{
    "data": [
        {
            "id": "17843857450040591"
        }
    ]
}

ハッシュタグ検索があまりヒットしない

特に問題なさそうなので、さっそくブランド名を10個程度配列に突っ込みハッシュタグ検索をかけてみましたが、ハッシュタグIDがうまくヒットしませんでした。最初は連投制限にでもひっかかっているのかと思い、sleep(10)とかを付けつつ回してみましたが、ヒット率は低いままでした。

リファレンスマニュアルを再度見てみましたが、ハッシュタグ名を入れろ(必須)といった程度のことしか書いてないので、役に立ちそうにありません。

Query String Parameters

{q} (required) — The hashtag name to query.

ハッシュタグ検索(IG Hashtag Search)リファレンス

レスポンスデータを再度見ると、うまくハッシュタグIDを取れているブランド名もあったものの、その場合もレスポンスのJSONにはハッシュタグIDは一つしか入っていないようです。もしかすると、検索したハッシュタグ名と全く同じ文字列でないとIDが取れないといった厳しい仕様なのかもしれません。

そうなると、設定するキーワード(ブランド名)側でしっかり調整しておかないと、ヒット率が全然上がらない気がしてきました。

例えば、「THE NORTH FACE」とかのブランド名だと、「#thenorthface」が公式インスタで使われているハッシュタグのようなので、空白詰めするとかが必要という感じです。。。このあたりは、まだまだ調整が必要そうです。

ハッシュタグ検索のエラー処理

file_get_contents()でJSONデータが取れなかった場合、HTTP request failed! HTTP/1.0 404が返ってしまうため、ぐるぐる回す場合には少々対策が必要となります。

そうなると「cURL」を使って書いた方が良いかもしれないですが、面倒なので、とりあえずやっつけでfile_get_contents()にエラー制御演算子@を付けて走らせてしまいました。

if($InstagramBuff = @file_get_contents($q)){
 //正常処理
}else{
 //エラー処理
}

ハッシュタグ関連投稿データ取得(IG Hashtag)

ハッシュタグIDが取れているものもあるので、そのハッシュタグIDを利用して投稿データを続いて取りにいってみます。

投稿データを取得できるIG Hashtag APIでは下記のような形でリクエストを生成する必要があります。リクエストURLの真ん中にハッシュタグIDを挟み込むという、少々見かけない形です。

https://graph.facebook.com/v12.0/「ハッシュタグID」/top_media?user_id=「ユーザID」&fields=id,media_type,media_url&access_token=「アクセストークン」

これを投げると、無事ハッシュタグでタグ付けされた投稿データをJSONで取得することができました。

{
   "data": [
      {
         "id": "17941976725826572",
         "media_type": "IMAGE",
         "media_url": "https://scontent-nrt1-1.cdninstagram.com/v/t51.29350-15/272928075_906331086747417_6659283842078070029_n.jpg?_nc_cat=105&ccb=1-5&_nc_sid=8ae9d6&_nc_ohc=oopojp3r3UcAX-MIs4n&_nc_ht=scontent-nrt1-1.cdninstagram.com&edm=APCawUEEAAAA&oh=00_AT_d3aO3_Lvb_NmZuZTpp597cSMPCYkZsW9JSkwOpklYCQ&oe=61FB22E9",
         "permalink": "https://www.instagram.com/p/CZWyXinpy_S/"
      },
      {
         "id": "17927656307072833",
         "media_type": "CAROUSEL_ALBUM",
         "permalink": "https://www.instagram.com/p/CZW9wUcD4-S/"
      }
   ],
   "paging": {
      "cursors": {
         "after": "ZAjIyYjVlNjcwMWU3NGU1OThiNDYxZAGY5NzFhNzlkMzIZD"
      },
      "next": "https://graph.facebook.com/v12.0/17843731993039459/top_media?access_token=EAAXNyGkUTSIBAIMbFwTRAKGG4qZCWijxtv4JOKKZChWYKxKbwMQpO4NCWmKjelGcTQuwpNGGcTNX9UsS79oms1B0aYH5BZBHTF17xIPeACOMliIPvFTmfsdqe50K5xgQaZAh4uP14SKFu4hZA8Sg8jNkrzHuvDmFMIKzz2LoYwMtQsS0sX2m6BMloEaXPV7gZD&pretty=1&fields=id\u00252Cmedia_type\u00252Cmedia_url\u00252Cpermalink&user_id=17841451916441349&limit=25&after=ZAjIyYjVlNjcwMWU3NGU1OThiNDYxZAGY5NzFhNzlkMzIZD"
   }
}

厄介なmedia_type : CAROUSEL_ALBUM

JSONデータを見れば分かると思いますが、取得できる投稿データにはIMAGE、VIDEOのほかに、CAROUSEL_ALBUMというものがあります。画像や動画2個以上の投稿時にはこのCAROUSEL_ALBUMというオブジェクトにまとめられてしまうようですが、media_type : CAROUSEL_ALBUMとなってしまうとすんなり投稿画像、動画のURLを取ることができなくなります。

CAROUSEL_ALBUMのオブジェクトではChildrenという固まりで投稿データをまとめているようで、リファレンスを見るとChildrenの中身取得用APIが別途用意されていました。

graph.facebook.com/「CAROUSEL_ALBUMのメディアID」/children

CAROUSEL_ALBUMのChildrenを一発で取得する技

@ricemountainerさんという方が詳しく説明してくれていましたが、IG HashtagのAPIリクエストに設定するfields値に、children{id,media_type,media_url}という形でfieldsパラメータを足しこんでおくと、一発でChildrenの中身まで取得が可能とのことでした。

実際やってみたところ、Childrenの中身まで一気に取ることができましたので、こちらでやることをオススメします。

https://graph.facebook.com/v12.0/「ハッシュタグID」/top_media?user_id=「ユーザID」&fields=id,media_type,media_url,children{id,media_type,media_url}&access_token=「アクセストークン」

投稿データのmedia_urlが無い場合もある

media_type : CAROUSEL_ALBUMのChildren問題もクリアできたので、これで問題ないだろうと思いJSONをパースしようとすると、まだエラーがでたりします。

どうやら、media_type :IMAGE、VIDEOであっても、media_urlが取得できないパターンというのがまれに存在するようです。著作権で保護されているコンテンツとか、そういった類のものかもしれませんが、レスポンスからmedia_urlが除外されてしまっておりました。

このため、データをパースする際に細工が必要そうですが、取り急ぎやっつけ対応をしてしまいました。

//JSON取得
$InstagramBuff = file_get_contents($q);

//オブジェクトに変換
$InstagramObj = new stdClass;
$InstagramObj = json_decode($InstagramBuff , false);

//ループ取得
foreach($InstagramObj -> data as $InstagramItem){

 //CAROUSEL_ALBUMの時はChildrenも
  if($InstagramItem -> media_type == "CAROUSEL_ALBUM"){

  foreach($InstagramItem -> children -> data as $InstagramChildrenItem){

   //メディアのURLが存在した場合だけ....
   if(!empty($InstagramChildrenItem->media_url)){
    ・・・データを取得・・・
   }
  }
 }
}

サイトに実装する

Instagram Graph APIの制限レートは200(回/時間)とはありましたが、連投をするとやはりコケそうな気がしたので、sleep(10)は残したままにしてcronで提示取得をしてmedia_urlをDBに貯め込むようにしてみました。

取得したデータをブランド詳細ページにカルーセルに仕立てて表示してあげて完成です。↓はハッシュタグ「#NIKE」に関連した投稿を表示させています。

PIでブランド名ハッシュタグのInstagram投稿データを表示
APIでブランド名ハッシュタグのInstagram投稿データを表示

ナイキブランドのブランド人気度推移ページ

https://trending.dtn.jp/brand/item/3

ブランド名でハッシュタグ検索をすると

「NIKE」「DIOR」といったブランド名であれば、ハッシュタグ検索をしてもすんなりヒットしますが、先ほどご紹介したように「THE NORTH FACE」のようなブランド名でヒットしてくれないところは、やはり何か考えないととは思いました。

それと、「Java」「moment+」といったブランド名の場合には、当然ながらハッシュタグがブランド名とは別の意味になってしまうため、タグ付けされた画像もブランドと全く関係ないものが表示されてしまうところも少々困ってしまいました。

そもそも、ブランド名を「Java」とかにしようとなったとき、なぜ誰も止めないんだろうかと不思議に思ってしまいます。。。

おわりに

Instagram Graph APIを使い、タグ付けされた投稿画像、動画を取得してサイトに表示させただけでしたが、お陰でパッとしないサイトが少し華やかになった気がしました。もう少しハッシュタグ検索のヒット率を上げたいところなので、その辺りは追々修正していきたいと思います。

APIの完成度、安定性ではtwitter APIの方が上という気はしましたが、貴重な画像・動画データをバンバン取得できますので、もっと大量に画像・動画データを収集して蓄積しておけば、色々と活用幅が広がりそうな気はします。是非皆さんもチャレンジしてみて下さい。

記事を読んで、PHP&SQL&APIでweb制作にチャレンジしてみたくなった方には、オンラインスクールでの短期集中学習などもあります。

ちなみに、本業で少々かかわるECでは、自社のInstagram投稿データをフロントに表示させるためだけに毎月結構な金額を某サービスに払っていたりします。APIで簡単に取れると分かっているだけに、たったこれだけをよくここまでサービスに仕立て上げて、この金額で請求するなと感心してしまいます。商売上手な人が羨ましいですね。