• トップ
  • ブログ一覧
  • 【GAS】instagram graph apiを使用してインサイトデータ入力を自動化
  • 【GAS】instagram graph apiを使用してインサイトデータ入力を自動化

    【GAS】instagram graph apiを使用してインサイトデータ入力を自動化してみた

    実装を行なった経緯

    知人が最近飲食店を始めたので、何か手伝えることがないか考えた結果あまり手伝えることがなかったので、instagramのデータを記入を自動化してみました。

    お店のためになったかは微妙ですが、データが力を発揮するのはまだまだ先だと思ってるのでひとまずよしとします。


    GASとは??

    Google App Scriptの略称。
    業務の進め方を最適化ができるGoogle Workspace の統合、自動化、拡張のためのビジネス ソリューションをすばやく簡単に構築するための唯一のローコード プラットフォームだと記載されています。
    参照:https://workspace.google.co.jp/intl/ja/products/apps-script/


    実装

    それでは早速実装に入っていきます。
    手順は以下の通りです。

    1. Instagram Gragh APIセットアップ
    2. 実装

    1.Instagram Gragh APIセットアップ
    どのウェブサイトでもこの「1.Instagram Gragh APIセットアップ」部分が最難関だと記載されています。
    手順としては、以下の通りです。

    1.アカウントタイプをプロアカウントに変更
    手順は以下の通りです。

    1. アプリの Instagram を開く
    2. プロフィールを開き、右上のメニューアイコン をタップ
    3. 「設定」をタップ
    4. 「アカウント」をタップ
    5. 「プロアカウントに切り替える」をタップ

    2.facebookとinstagramを連携(facebookアカウントがない場合は作成してください)
    手順は以下の通りです。

    1. アプリのInstagramを開く
    2. プロフィール画面にて「プロフィール編集」をタップ
    3. ビジネスの「ページ」の「リンクまたは作成」をタップ

    3.Facebookアプリを作る
    手順は以下の通りです。

    1. Facebook Developers(開発者ツール)を開く
    2. [マイアプリ]→[アプリの作成]をタップ
    3. ユースケース:その他、アプリタイプはビジネス、アプリ名は任意で入力
    4. [ツール]→[グラフAPIエクスプローラ]を選択してグラフAPIエクスプローラを表示

    4.必要な情報(トークンなど)を取得
    手順は以下の通りです。
    下記画像を参考にアクセスを許可(Facebookにログイン認証する画面が出ます)
    赤枠で囲われている[ i ]を押して[アクセストークンツールで開く]をタップ

    [アクセストークンツールで開く]をタップするとアクセストークンデバッガーが表示される

    1. 画面下にある[アクセストークンを延長]をタップ
    2. 有効期限2ヶ月の長期アクセストークン情報が表示されるので、[デバッグ]をタップしてアクセストークンデバッガーで確認
    3. 画面上部にあるアクセストークンをコピー
    4. 再度[グラフAPIエクスプローラ]を開く
    5. アクセストークンに先程コピーした[有効期限2ヶ月のアクセストークン]を入力
    6. 下記画像を参考に上部のバーに[me/accounts]と入力
    7. 送信をタップ
    8. 表示された「access_token」をコピー(下記画像参考)
      「有効期限無期限のアクセストークン」になるので、必ず控えてください
    9. 再度[グラフAPIエクスプローラ]を開く
    10. 下記画像を参考に上部のバーに[me?fields=accounts{instagram_business_account}]と入力
    11. 送信をタップ
    12. 表示された「instagramのid」をコピー(下記画像参考)
      「instagram_business_id」になるので、必ず控えてください

    以上でInstagram Gragh APIセットアップは完了になります。

    2.実装
    今回作成するのは、下記3つのシートです。

    1. フォロー/フォロワー/投稿数を管理する「フォロ・フォロワー」シート
    2. アカウント全体のインサイトを管理する「インサイト」シート
    3. 投稿別のインサイトを管理する「投稿別インサイト」シート

    ※スプレットシートを操作方法は、本記事では割愛させていただきます。

    シートの作成が完了したら、app scriptを開きます。

    scriptが開けたら、共通の処理をまとめる「common.gs」ファイルをscript内に作成します。

    common.gs

    1// 共通処理、定数などを定義
    2
    3const INSTAGRAM_ID = `{apiセットアップ時に控えたInstagramID}`;
    4const ACCESS_TOKEN = `{apiセットアップ時に控えたAccessToken}`;
    5// https://docs.google.com/spreadsheets/d/{この部分がSSID}/edit#gid=0
    6const SSId = `{SSID}`;
    7const USER_NAME = `{Instagramのアカウント名}`;
    8// シート読み込み
    9function loadSheet(sheetName) {
    10  let mySS = SpreadsheetApp.openById(SSId); //IDでスプレッドシートを開く
    11  return mySS.getSheetByName(sheetName);
    12}
    13// データ取得
    14function fetchData(facebook_url) {
    15  let encodedURI = encodeURI(facebook_url);
    16  let response = UrlFetchApp.fetch(encodedURI); //URLから情報を取得
    17  return JSON.parse(response);//JSONデータをパース
    18}
    19//行の存在に応じて追加もしくは更新を行う
    20function insertOrUpdate(sheet, data) {
    21  let row = findRow(sheet, data[0]);//日付比較の関数、行番号を受け取る
    22  if (row) { // 行が見つかったら更新
    23    sheet.getRange(row, 1, 1, data.length).setValues([data]);
    24  } else { // 行が見つからなかったら新しくデータを挿入
    25  sheet.appendRow(data);
    26  }
    27}
    28// 日付比較を行い、データがあれば行番号を返す
    29function findRow(sheet, date) {
    30  let searchDate = Utilities.formatDate(new Date(date), `Asia/Tokyo`,`yyyy/MM/dd`);
    31  let values = sheet.getDataRange().getValues();
    32  for (let i = values.length - 1; i > 0; i--) {
    33    let dataDate = Utilities.formatDate(new Date(values[i][0]), `Asia/Tokyo`,`yyyy/MM/dd`);
    34    if (dataDate == searchDate) {
    35      return i + 1;
    36    }
    37  }
    38  return false

    上記コードは共通の処理や定数をまとめています。


    次に「フォロー・フォロワー」の数を記録するコードを実装していきます。

    follow.gs

    1function reporting() {
    2  const sheetName = `フォロー・フォロワー`;
    3  // シートを読み込み
    4  const sheet = loadSheet(sheetName);
    5
    6  // 今日の日付
    7  const today = new Date();
    8  const formattedDate = formatDate(today, `Asia/Tokyo`, `yyyy/MM/dd`);
    9
    10  // Facebook Graph API URL
    11  const facebookUrl = `https://graph.facebook.com/v4.0/${INSTAGRAM_ID}?fields=business_discovery.username(${USER_NAME}){followers_count,follows_count,media_count}&access_token=${ACCESS_TOKEN}`;
    12
    13  // データを取得
    14  const insightData = fetchData(facebookUrl);
    15
    16  // データを格納
    17  const followers = insightData[`business_discovery`][`followers_count`];
    18  const follows = insightData[`business_discovery`][`follows_count`];
    19  const mediaCount = insightData[`business_discovery`][`media_count`];
    20  const followerDifferenceValue = followerDifference(followers, sheet);
    21
    22  // シートにデータを追加または更新
    23  insertOrUpdate(sheet, [formattedDate, followers, follows, mediaCount, followerDifferenceValue]);
    24}
    25
    26// 前日のフォロワーとの差分を取得
    27function followerDifference(todayFollowersCount, sheet) {
    28  const lastRow = sheet.getLastRow();
    29  // 1日前のフォロワー数を取得(2はB列を指す)
    30  const oneDayAgoFollowersCount = sheet.getRange(lastRow, 2).getDisplayValue();
    31  // 差分を返す
    32  return todayFollowersCount - oneDayAgoFollowersCount;
    33}
    34
    35// フォーマット関数
    36function formatDate(date, timeZone, format) {
    37  return Utilities.formatDate(date, timeZone, format);
    38}

    次に「インサイト」を記録するコードを実装していきます。
    insight.gs

    1function insightReporting() {
    2  const sheetName = `インサイト`;
    3
    4  // シートを読み込み
    5  const sheet = loadSheet(sheetName);
    6
    7  // 1日前の日付を取得
    8  const yesterday = getYesterday(new Date());
    9
    10  // Graph API URL
    11  const facebookUrl = `https://graph.facebook.com/v8.0/${INSTAGRAM_ID}/insights?metric=reach,impressions,profile_views&period=day&access_token=${ACCESS_TOKEN}`;
    12
    13  // データを取得
    14  const insightData = fetchData(facebookUrl);
    15
    16  // データを格納
    17  const reach = getMetricValue(insightData, `reach`);
    18  const impressions = getMetricValue(insightData, `impressions`);
    19  const profileViews = getMetricValue(insightData, `profile_views`);
    20
    21  // シートにデータを追加または更新
    22  insertOrUpdate(sheet, [yesterday, reach, impressions, profileViews]);
    23}
    24
    25function getYesterday(date) {
    26  // 現在の日付を取得して1日前に戻す
    27  date.setDate(date.getDate() - 1);
    28  // 日付を整形して返す
    29  return Utilities.formatDate(date, `JST`, `yyyy/MM/dd`);
    30}
    31
    32function getMetricValue(insightData, metric) {
    33  // メトリクスの値を取得
    34  return insightData.data.find(data => data.name === metric).values[1].value;
    35}

    最後に「投稿別インサイト」を記録するコードを実装していきます。
    post.gs

    1function postReporting() {
    2  const sheetName = `投稿別インサイト`;
    3
    4  // シートを読み込み
    5  const sheet = loadSheet(sheetName);
    6  const num = 1000;
    7
    8  // データをクリア
    9  deleteSheetContents(sheet);
    10
    11  // Graph API URL
    12  const facebookUrl = `https://graph.facebook.com/v7.0/${INSTAGRAM_ID}?fields=media.limit(${num}){timestamp,like_count,comments_count,permalink}&access_token=${ACCESS_TOKEN}`;
    13
    14  // データを取得
    15  let insightData;
    16  try {
    17    insightData = fetchData(facebookUrl);
    18  } catch (error) {
    19    return;
    20  }
    21
    22  // 投稿の数だけ実行
    23  insightData[`media`][`data`].forEach(function(mediaData) {
    24    // mediaData[`id`]を使用して投稿別のインサイトデータを取得するためIDは必須
    25    if (mediaData[`id`]) {
    26      // Graph API URL
    27      const postInsightUrl = `https://graph.facebook.com/v18.0/${mediaData[`id`]}/insights?metric=impressions,reach,saved&access_token=${ACCESS_TOKEN}`;
    28
    29      // データを取得
    30      let postInsightData;
    31      try {
    32        postInsightData = fetchData(postInsightUrl);
    33      } catch (error) {
    34        return;
    35      }
    36
    37      // データを格納
    38      const timestamp = new Date(mediaData[`timestamp`]);
    39      const likeCount = mediaData[`like_count`];
    40      const commentsCount = mediaData[`comments_count`];
    41      let impressions, reach, saved;
    42      postInsightData[`data`].forEach(function(insight) {
    43        switch (insight[`name`]) {
    44          case `impressions`:
    45            impressions = insight.values[0].value;
    46            break;
    47          case `reach`:
    48            reach = insight.values[0].value;
    49            break;
    50          case `saved`:
    51            saved = insight.values[0].value;
    52            break;
    53        }
    54      });
    55      const permalink = mediaData[`permalink`];
    56
    57      // シートに書き込み
    58      sheet.getRange(sheet.getLastRow() + 1, 1).setValue(Utilities.formatDate(timestamp, `Asia/Tokyo`, `yyyy/MM/dd HH:mm:ss`));
    59      sheet.getRange(sheet.getLastRow(), 2, 1, 6).setValues([[likeCount, commentsCount, impressions, reach, saved, permalink]]);
    60    }
    61  });
    62}
    63
    64function deleteSheetContents(sheet) {
    65  // 最終行と最終列の取得
    66  var lastRow = sheet.getLastRow();
    67  var lastColumn = sheet.getLastColumn();
    68  // データが存在するかチェック
    69  if (lastRow > 1) { // データが1行以上存在する場合
    70    // 範囲を取得
    71    var range = sheet.getRange(2, 1, lastRow - 1, lastColumn); // カラム行はクリア対象外にしたいので -1
    72    // データをクリア(4パターン)
    73    range.clear(); // 値・書式
    74    // range.clearContent(); // 値のみ (これを有効にするかどうかは要件によります)
    75    range.clearFormat(); // 書式のみ
    76    range.clearDataValidations(); // 入力規則
    77  }
    78}

    これで実装部分は完了です。


    残りは、いつこの処理を実行するのかを指定します。
    「いつ」処理を実行するのかを決めるには、「トリガー」を使用します。

    scriptの画面に戻り下記画像赤枠部分がトリガー一覧画面で処理の実行タイミングを決定します。

    「トリガー」一覧画面に遷移後右下にある「トリガーの追加」ボタンを押下し先ほど実装した処理を定期実行できるよう設定します。

    下記モーダルが開いたら、赤枠部分の「実行する関数」関数「時間ベースのトリガーのタイプ」「時間の間隔」を設定します。
    日付ベース、年ベースなどあるのでご自身お好きな実行タイミングを実行してください。

    これでトリガーの設定は完了です。


    参考資料

    apiセットアップ

    1. https://navymobile.co.jp/instagram-graph-api
      実装
    2. https://qiita.com/joh_luck/items/af6f02c43e2f4497e15e

    実行結果

    1. フォロー/フォロワー/投稿数を管理する「フォロ・フォロワー」シート
    2. アカウント全体のインサイトを管理する「インサイト」シート
    3. 投稿別のインサイトを管理する「投稿別インサイト」シート

    ※アプリのinstagramを開き、実際に出力されているデータが正しいか確認してください。


    終わりに

    いかがだったでしょうか?
    ほぼ初めてGASを使用しましたが、環境構築も必要なく簡単に実装からはいれるので実装者としてはとてもありがたかったです。
    まだまだ業務効率化は可能だと思うので、sns関係に限らずお店の効率化を勝手に図っていきたいと思います。

    ライトコードでは、エンジニアを積極採用中!

    ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。

    採用情報へ

    かねまさ(エンジニア)
    かねまさ(エンジニア)
    Show more...

    おすすめ記事

    エンジニア大募集中!

    ライトコードでは、エンジニアを積極採用中です。

    特に、WEBエンジニアとモバイルエンジニアは是非ご応募お待ちしております!

    また、フリーランスエンジニア様も大募集中です。

    background