instagram graphAPIでアカウントデータの取得

instagram graphAPIでアカウントデータの取得
==

エラー### 事前にやっておくこと
1. GASの設定(parserの追加)
1. . Instagram GraphAPIからトークン、ユーザーID、バージョンの取得
1. . ②から取得した情報を上記の内容をスプレッドシートに記載。
　私は以下のようにアクセストークンを記載しています。

![アクセストークン02.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3298246/d423f815-2658-cd53-52e5-7629f69e3a69.jpeg)




### これからやろうとしている手順
①メイン関数の作成
　事前に取得したトークンを用いて、②以降の関数を実行。

②アカウント情報を取得する関数の作成
　ビジネスディスカバリーでアカウントのプロフィール情報を取得。



1. メイン関数の作成
==
### 事前に準備したスプレッドシートを読み込み
SpreadsheetApp.openByUrl()内に''付きでスプレッドシートのURLを貼り付けます。
```javascript：
let spreadsheet = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/*****');
```

### アクセストークンを書き込んだシートを取得
取得したスプレッドシートのアクセストークンを記載したシートの内容を取得します。
spreadsheet.getSheetByName()内に''付きでシート名を書きます。
```javascript：
let sheet = spreadsheet.getSheetByName('インスタアクセストークン'); //アクセストークン記載シート読み込み
```

### Instagram Graph API認証情報を取得
取得したシートからアクセストークン・ユーザーID・ユーザーネームを取得します。
```javascript：
let accesstoken =  sheet.getRange(11, 1).getValue();
  let account_id =  sheet.getRange(12, 2).getValue();
  let username =  sheet.getRange(13, 2).getValue();
```
### これまで作成したメイン関数をまとめるとこんな感じ
```
function main() {
  let spreadsheet = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/*****);
  let sheet = spreadsheet.getSheetByName('インスタアクセストークン'); //アクセストークン記載シート読み込み

  
  // Instagram Graph API認証情報
  let accesstoken =  sheet.getRange(11, 2).getValue();
  let account_id =  sheet.getRange(12, 2).getValue();
  let username =  sheet.getRange(13, 2).getValue();
}
```
2.アカウント情報を取得する
==
### ビジネスディスカバリーのエンドポイントの設定
アカウントから取得する情報が「fields=business_discovery.」以降の内容になります。
これらの内容について取得しています。
#### ユーザー情報（プロフィールなど）
　- ユーザー名
　- webサイト
　- 名前、ID
　- プロフィール画像
　- 自己紹介文
　- フォロー数、フォロワー数
　- 投稿数

#### 投稿情報
　- 投稿日付
　- いいね数
　- コメント数
　- 投稿のキャプションテキスト
　- メディアのURL
　- メディアのタイプ(IMAGE、VIDEO、CAROUSEL_ALBUMのいずれか)
```
let graph_domain = 'https://graph.facebook.com/'
let graph_version = 'v15.0';
let endpoint_base = graph_domain + graph_version + '/';

let  url = endpoint_base + account_id;

let params ='?fields=business_discovery.username({user_id}){username, website, name, id, profile_picture_url, biography, follows_count,followers_count, media_count, media{timestamp, like_count, comments_count, caption, media_url,media_type}};

let endpoint_url = url + params + '&access_token=' +accesstoken;
```

### getリクエストの送信
作成したエンドポイントをPCで読み込むために、文字の変換をします。
こちらにもわかりやすく書いてあるので参考にしてください。
https://www.sejuku.net/blog/58913

```
endpointURI = encodeURI(endpoint_url); // 文字変換
const options = {muteHttpExceptions:true};
const response = UrlFetchApp.fetch(endpointURI , options);
```

#### リクエスト送信時のエラー文の表示
リクエストを送信後、エラーが発生する場合があります。
エラー理由がわかるようにエラー文を出力されるようにします。
```
if (response.getResponseCode() !== 200) {
     throw new Error('エラーのため取得できませんでした');
   } else {
     var res =  JSON.parse(response.getContentText("utf-8"));
   }
```  

#### JSON文字列を辞書に変換
```  
let array=Parser.data(res)
```  

### これまで作成したメイン関数をまとめるとこんな感じ
call_bussiness_profile()内に、
main()関数で定義したものを書きます。
#### main()関数内に記載する内容
以下の引数を入れます。
call_bussiness_profile(accesstoken,account_id,user_id)


```
function call_bussiness_profile(accesstoken,account_id,user_id){

  //ビジネスディスカバリーのエンドポイントの設定
  let graph_domain = 'https://graph.facebook.com/'
  let graph_version = 'v15.0';
  let endpoint_base = graph_domain + graph_version + '/';

  //ビジネスディスカバリーのパラメータ設定

  let  url = endpoint_base + account_id;
  let params ='?fields=business_discovery.username(' + user_id + ')\
  {username, website, name, id, profile_picture_url, biography,follows_count,followers_count, media_count,\
  media{timestamp, like_count, comments_count, caption, media_url}\
  }';
  
  let endpoint_url = url + params + '&access_token=' +accesstoken;

  endpointURI = encodeURI(endpoint_url); // 文字変換

  const options = {muteHttpExceptions:true};
  const response = UrlFetchApp.fetch(endpointURI , options);
  
  //リクエスト送信時のエラー文の表示
  if (response.getResponseCode() !== 200) {
        throw new Error('エラーのため取得できませんでした');
      } else {
        var res =  JSON.parse(response.getContentText("utf-8"));
      }
  
  //JSON文字列を辞書に変換
  let array=Parser.data(res);
  return array
}
```

3.投稿数を追加で取得する
==
2で取得できる投稿数は25件となっています。
なので25件以上の投稿についても情報を取得していきます。

#### これからやること
1. 25ページ以降が記載されているエンドポイントを取得
1. エンドポイントから25件以降の投稿数を取得する


```javascript：
// ページ送りのafter_keyを取得する
  after_key = ''
  // //  after_keyがある場合

  try {
    //  after_keyがある場合
    let after_key = account_dict['business_discovery']['media']['paging']['cursors']['after'];
  }catch(e){
    //  after_keyがない場合
    Logger.log('Error')
    Logger.log(e)≒≧
    return after_key
  }
}
```

## ユーザー名とafter_keyを受け取り、追加データ分を再度ビジネスディスカバリーでデータを取得する

### 1. 先ほど取得したafter_keyからエンドポイントを作成

```javascript：
 let params ='?fields=business_discovery.username(' + user_id + ')\
  {media.after(' + after_key + ').limit(' + media_count + '){timestamp, like_count, comments_count, caption, media_url,media_type}}'
  // {media.after(' + after_key + ').limit(' + media_count + '){timestamp, like_count, comments_count}}'

  let api_pagenation =  url + params + '&access_token=' +accesstoken;
```
### 2.　1のリクエストの送信＆文字列へ変換
```
//リクエスト送信
  endpointURI = encodeURI(api_pagenation); 
  let options = {muteHttpExceptions:true};
  let response = UrlFetchApp.fetch(endpointURI , options);
//文字列へ変換
  let res =  JSON.parse(response.getContentText("utf-8"));
```
## 3「投稿数を追加で取得する」の内容ををまとめるとこんな感じ
```javascript：
function after_key_get(account_dict){
  // ページ送りのafter_keyを取得する
  try {
    after_key =account_dict['business_discovery']['media']['paging']['cursors']['after'];
  }catch(e){
  //  after_keyがない場合
    Logger.log('Error')
    Logger.log(e)
  }
  //  after_keyがある場合
  // console.log(after_key)
  return after_key
}

function api_error(acccount_dict){
  //  API制限に引っかかった場合の処理

  if (account_dict['error']['code'] == 4){
  console.log('API制限に引っかかった場合の処理')
  console.log('プログラムを終了します。')
  }
}

function pagenate(url,accesstoken,user_id,after_key,media_count){
  // 

  // ビジネスディスカバリーのページ送りのエンドポイントの設定  
  let params ='?fields=business_discovery.username(' + user_id + ')\
  {media.after(' + after_key + ').limit(' + media_count + '){timestamp, like_count, comments_count, caption, media_url,media_type}}'
  // {media.after(' + after_key + ').limit(' + media_count + '){timestamp, like_count, comments_count}}'
  
  let api_pagenation =  url + params + '&access_token=' +accesstoken;
  endpointURI = encodeURI(api_pagenation); // 文字変換
  let options = {muteHttpExceptions:true};
  let response = UrlFetchApp.fetch(endpointURI , options);
  let res =  JSON.parse(response.getContentText("utf-8"));

  return res
}
```
4.スプレッドシートに書き込み
==
2~3で取得した内容をスプレッドシートに書き込みします。

#### これからやること
1. makesheet_account関数で作成
1. スプレッドシートにユーザーIDのシートを作成
1. 投稿毎のデータ行列を作成
1. スプレッドシートへ書き込み

## スプレッドシートにユーザーIDのシートを作成
スプレッドシートにユーザーIDのシートを作成をします。
- 同じ名前のスプレッドシートがない　→　新規作成
- 同じ名前のスプレッドシートがある　→　すでにあるシートを空白にする

```
function makesheet_account(spreadsheet,sheetname){
  //シート作成
  try{
    //データシートの取得
    let sheet = spreadsheet.getSheetByName(sheetname);
    if(sheet){
      sheet.clear();
    }else{
      spreadsheet.insertSheet(sheetname);
    }
  }catch(e) { //エラー発生時
  return e.toString();
  }
}
```

## 投稿毎のデータ行列を作成
2~3で得た投稿毎のデータを行列するために
writesheet_media関数を作成します。
### 1. 以下の内容ごとの空の行列を作成します。
　- 投稿日付
　- いいね数
　- コメント数
　- 投稿のキャプションテキスト
　- メディアのURL
　- メディアのタイプ

```
  let media_timestamp = new Array;
  let media_like_count = new Array;
  let media_comments_count = new Array;
  let media_caption = new Array;
  let media_media_url = new Array;
  let media_media_type = new Array;
```

### 2. 2~3で得た投稿毎のデータをからの行列にfor文を用いて追加

```

  for(let i=1 ; i < count; i++){
  media_timestamp[i]= dict['business_discovery']['media']['data'][i]['timestamp'];
  media_like_count[i] = dict['business_discovery']['media']['data'][i]['like_count'];
  media_comments_count[i]= dict['business_discovery']['media']['data'][i]['comments_count'];
  media_caption[i] = dict['business_discovery']['media']['data'][i]['caption'];
  media_media_type[i] = dict['business_discovery']['media']['data'][i]['media_type'];
```
### 投稿画像がないとき
エラーにならないように、投稿画像が空のときは空白で入力
```
  try{
    //投稿画像がない場合
    dict['business_discovery']['media']['data'][i]['media_url']
    if(dict['business_discovery']['media']['data'][i]['media_url']){
      media_media_url[i]= dict['business_discovery']['media']['data'][i]['media_url'];
    }else{}
  }catch(e){
    media_media_url[i]=""
  }
```

## スプレッドシートへ書き込み

setValueを用いてスプレッドシートに書き込み
各列のタイトルも合わせて書き込みします。
```
    if(writeSheet.getLastRow() > 1){
  }else{
    writeSheet.getRange(1,1).setValue("投稿日");
    writeSheet.getRange(1,2).setValue("いいね数");
    writeSheet.getRange(1,3).setValue("コメント数"); 
    writeSheet.getRange(1,4).setValue("メディアのURL"); 
    writeSheet.getRange(1,5).setValue("メディアのタイプ"); 
    writeSheet.getRange(1,6).setValue("テキスト"); 
  }
  for(let i=1 ; i < count; i++){
    writeSheet.getRange(i+lastrow,1).setValue(media_timestamp[i]);
    writeSheet.getRange(i+lastrow,2).setValue(media_like_count[i]);
    writeSheet.getRange(i+lastrow,3).setValue(media_comments_count[i]);
    writeSheet.getRange(i+lastrow,4).setValue(media_media_url[i]);
    writeSheet.getRange(i+lastrow,5).setValue(media_media_type[i]);
    writeSheet.getRange(i+lastrow,6).setValue(media_caption[i]);
  }
```
## 4「スプレッドシートに書き込み」の内容ををまとめるとこんな感じ
```javascript：
function writesheet_media(spreadsheet,sheetname,dict){
  //シートの取得
  let writeSheet = spreadsheet.getSheetByName(sheetname);

  if(writeSheet.getLastRow() > 1){
  }else{
    writeSheet.getRange(1,1).setValue("投稿日");
    writeSheet.getRange(1,2).setValue("いいね数");
    writeSheet.getRange(1,3).setValue("コメント数"); 
    writeSheet.getRange(1,4).setValue("メディアのURL"); 
    writeSheet.getRange(1,5).setValue("メディアのタイプ"); 
    writeSheet.getRange(1,6).setValue("テキスト"); 
  }

  // 最終行の取得
  lastrow = writeSheet.getLastRow();

  let count = dict['business_discovery']['media']['data'].length;

  // let media_data = new Array;

  let media_timestamp = new Array;
  let media_like_count = new Array;
  let media_comments_count = new Array;
  let media_caption = new Array;
  let media_media_url = new Array;
  let media_media_type = new Array;


  for(let i=1 ; i < count; i++){
  media_timestamp[i]= dict['business_discovery']['media']['data'][i]['timestamp'];
  media_like_count[i] = dict['business_discovery']['media']['data'][i]['like_count'];
  media_comments_count[i]= dict['business_discovery']['media']['data'][i]['comments_count'];
  media_caption[i] = dict['business_discovery']['media']['data'][i]['caption'];
  media_media_type[i] = dict['business_discovery']['media']['data'][i]['media_type'];

  try{
    //投稿画像がない場合
    dict['business_discovery']['media']['data'][i]['media_url']
    if(dict['business_discovery']['media']['data'][i]['media_url']){
      media_media_url[i]= dict['business_discovery']['media']['data'][i]['media_url'];
    }else{}
  }catch(e){
    media_media_url[i]=""
  }
  

  // media_data[i]['like_count'] = dict['business_discovery']['media']['data'][i]['like_count'];
  // media_data[i]['comments_count'] = dict['business_discovery']['media']['data'][i]['comments_count'];
  // media_data[i]['caption'] = dict['business_discovery']['media']['data'][i]['caption'];
  // media_data[i]['media_url'] = dict['business_discovery']['media']['data'][i]['media_url'];
  // media_data[i]['media_type'] = dict['business_discovery']['media']['data'][i]['media_type'];
  //ハッシュタグ抽出保留
  // hash_tag_list = re.findall('#([^\s→#\ufeff]*)', caption)
  // hash_tags = '\n'.join(hash_tag_list)
  }

  for(let i=1 ; i < count; i++){
    writeSheet.getRange(i+lastrow,1).setValue(media_timestamp[i]);
    writeSheet.getRange(i+lastrow,2).setValue(media_like_count[i]);
    writeSheet.getRange(i+lastrow,3).setValue(media_comments_count[i]);
    writeSheet.getRange(i+lastrow,4).setValue(media_media_url[i]);
    writeSheet.getRange(i+lastrow,5).setValue(media_media_type[i]);
    writeSheet.getRange(i+lastrow,6).setValue(media_caption[i]);
  }
}
```

5.これまで関数からmain関数の作成
===
### ２～４までの内容からmain関数を作る
```
Function main() {
  let spreadsheet = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/1WzYY1mUdoZjTwz6B8cYl_twhsYwdJeFXtn49CLeoc0M/edit#gid=0');
  let sheet = spreadsheet.getSheetByName('インスタアクセストークン'); //アクセストークン記載シート読み込み
  //ユーザーIDを入力
  user_id = "***"

  
  // Instagram Graph API認証情報
  let accesstoken =  sheet.getRange(11, 2).getValue();
  let account_id =  sheet.getRange(12, 2).getValue();
  let username =  sheet.getRange(13, 2).getValue();

  
  //ビジネスディスカバリーのエンドポイントの設定
  let graph_domain = 'https://graph.facebook.com/'
  let graph_version = 'v16.0';
  let endpoint_base = graph_domain + graph_version + '/';
  let url = endpoint_base + account_id;

  // ユーザーIDを使ってビジネスディスカバリー情報の取得
  account_dict = call_bussiness_profile(url,accesstoken,account_id,user_id);
  let media_count = account_dict['business_discovery']['media_count'];
  bussiness_accountsheet = makesheet_account(spreadsheet,user_id);
  //スプレッドシートへ書き込み
  writesheet_media(spreadsheet,user_id,account_dict);


  // after_keyがあれば、追加でデータを取得
  let after_key =after_key_get(account_dict);
  if(after_key){
    pagenate_dict = pagenate(url,accesstoken,user_id,after_key,media_count);
    pagenate_data = pagenate_dict['business_discovery']['media']['data'];
  }else{
  // after_keyがない場合　そのままデータフレームを作成
  console.log('after_keyがありませんでした。');
  }
  //スプレッドシートへ書き込み
  writesheet_media(spreadsheet,user_id,pagenate_dict);
}
```

【完成版】
===

```
function main() {：
  let spreadsheet = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/*****');
  let sheet = spreadsheet.getSheetByName('インスタアクセストークン'); //アクセストークン記載シート読み込み
  //ユーザーIDを入力
  user_id = "***"

  
  // Instagram Graph API認証情報
  let accesstoken =  sheet.getRange(11, 2).getValue();
  let account_id =  sheet.getRange(12, 2).getValue();
  let username =  sheet.getRange(13, 2).getValue();

  
  //ビジネスディスカバリーのエンドポイントの設定
  let graph_domain = 'https://graph.facebook.com/'
  let graph_version = 'v16.0';
  let endpoint_base = graph_domain + graph_version + '/';
  let url = endpoint_base + account_id;

  // ユーザーIDを使ってビジネスディスカバリー情報の取得
  account_dict = call_bussiness_profile(url,accesstoken,account_id,user_id);
  let media_count = account_dict['business_discovery']['media_count'];
  bussiness_accountsheet = makesheet_account(spreadsheet,user_id);
  //スプレッドシートへ書き込み
  writesheet_media(spreadsheet,user_id,account_dict);


  // after_keyがあれば、追加でデータを取得
  let after_key =after_key_get(account_dict);
  if(after_key){
    pagenate_dict = pagenate(url,accesstoken,user_id,after_key,media_count);
    pagenate_data = pagenate_dict['business_discovery']['media']['data'];
  }else{
  // after_keyがない場合　そのままデータフレームを作成
  console.log('after_keyがありませんでした。');
  }
  //スプレッドシートへ書き込み
  writesheet_media(spreadsheet,user_id,pagenate_dict);
}


function call_bussiness_profile(url,accesstoken,account_id,user_id){
  //ビジネスディスカバリーのパラメータ設定
  let params ='?fields=business_discovery.username(' + user_id + ')\
  {username, website, name, id, profile_picture_url, biography,follows_count,followers_count, media_count,\
  media{timestamp, like_count, comments_count, caption, media_url,media_type}\
  }';
  
  let endpoint_url = url + params + '&access_token=' +accesstoken;

  endpointURI = encodeURI(endpoint_url); // 文字変換

  let options = {muteHttpExceptions:true};
  let response = UrlFetchApp.fetch(endpointURI , options);
  let res =  JSON.parse(response.getContentText("utf-8"));
    
  return res
}

function after_key_get(account_dict){
  // ページ送りのafter_keyを取得する
  try {
    after_key =account_dict['business_discovery']['media']['paging']['cursors']['after'];
  }catch(e){
  //  after_keyがない場合
    Logger.log('Error')
    Logger.log(e)
  }
  //  after_keyがある場合
  // console.log(after_key)
  return after_key
}

function api_error(acccount_dict){
  //  API制限に引っかかった場合の処理

  if (account_dict['error']['code'] == 4){
  console.log('API制限に引っかかった場合の処理')
  console.log('プログラムを終了します。')
  }
}

function pagenate(url,accesstoken,user_id,after_key,media_count){
  // ビジネスディスカバリーのページ送りのエンドポイントの設定  
  let params ='?fields=business_discovery.username(' + user_id + ')\
  {media.after(' + after_key + ').limit(' + media_count + '){timestamp, like_count, comments_count, caption, media_url,media_type}}'
  // {media.after(' + after_key + ').limit(' + media_count + '){timestamp, like_count, comments_count}}'
  
  let api_pagenation =  url + params + '&access_token=' +accesstoken;
  endpointURI = encodeURI(api_pagenation); // 文字変換
  let options = {muteHttpExceptions:true};
  let response = UrlFetchApp.fetch(endpointURI , options);
  let res =  JSON.parse(response.getContentText("utf-8"));
  
  return res
}

unction makesheet_account(spreadsheet,sheetname){
  //シート作成
  try{
    //データシートの取得
    let sheet = spreadsheet.getSheetByName(sheetname);
    if(sheet){
      sheet.clear();
    }else{
      spreadsheet.insertSheet(sheetname);
    }
  }catch(e) { //エラー発生時
  return e.toString();
  }
}

function writesheet_media(spreadsheet,sheetname,dict){
  //シートの取得
  let writeSheet = spreadsheet.getSheetByName(sheetname);

  if(writeSheet.getLastRow() > 1){
  }else{
    writeSheet.getRange(1,1).setValue("投稿日");
    writeSheet.getRange(1,2).setValue("いいね数");
    writeSheet.getRange(1,3).setValue("コメント数"); 
    writeSheet.getRange(1,4).setValue("メディアのURL"); 
    writeSheet.getRange(1,5).setValue("メディアのタイプ"); 
    writeSheet.getRange(1,6).setValue("テキスト"); 
  }

  // 最終行の取得
  lastrow = writeSheet.getLastRow();

  let count = dict['business_discovery']['media']['data'].length;

  // let media_data = new Array;

  let media_timestamp = new Array;
  let media_like_count = new Array;
  let media_comments_count = new Array;
  let media_caption = new Array;
  let media_media_url = new Array;
  let media_media_type = new Array;


  for(let i=1 ; i < count; i++){
  media_timestamp[i]= dict['business_discovery']['media']['data'][i]['timestamp'];
  media_like_count[i] = dict['business_discovery']['media']['data'][i]['like_count'];
  media_comments_count[i]= dict['business_discovery']['media']['data'][i]['comments_count'];
  media_caption[i] = dict['business_discovery']['media']['data'][i]['caption'];
  media_media_type[i] = dict['business_discovery']['media']['data'][i]['media_type'];

  try{
    //投稿画像がない場合
    dict['business_discovery']['media']['data'][i]['media_url']
    if(dict['business_discovery']['media']['data'][i]['media_url']){
      media_media_url[i]= dict['business_discovery']['media']['data'][i]['media_url'];
    }else{}
  }catch(e){
    media_media_url[i]=""
  }
 for(let i=1 ; i < count; i++){
    writeSheet.getRange(i+lastrow,1).setValue(media_timestamp[i]);
    writeSheet.getRange(i+lastrow,2).setValue(media_like_count[i]);
    writeSheet.getRange(i+lastrow,3).setValue(media_comments_count[i]);
    writeSheet.getRange(i+lastrow,4).setValue(media_media_url[i]);
    writeSheet.getRange(i+lastrow,5).setValue(media_media_type[i]);
    writeSheet.getRange(i+lastrow,6).setValue(media_caption[i]);
  }

```


【おまけ】 ビジネスディスカバリー情報の取得結果が「Object」となる
==
### ビジネスディスカバリー情報の取得結果が「Object」となり、いいね数やコメント数わからないとき

作成したエンドポイント（endpoint_url）を出力し、ブラウザに入力すると表示されます。
なので実際は「Object」の中にいいね数やコメント数が出力されているので安心してください。


【おまけ】UrlFetchApp.fetch()のoptionとは？getContentText()とは？
==
### UrlFetchApp.fetch()内のoptionは、「muteHttpExceptions：true」
リクエストに失敗したときに、エラー全文を見るために、muteHttpExceptions オプションを使用します。

### getContentText()で出力結果をテキストとして出力
リクエスト結果をテキストとして取得します。
ちなみに getContentText()がない場合は、「Function」などと出力されます。