Instagram API利用時のメモです。
今回は、Instagramの任意のユーザーの新着を取得するのに必要な手順で、それ以外の利用方法は今回のメモの対象外です。
まず、事前知識として知っておくと理解が早い情報
- 一般公開されている写真の情報を取得するだけでもAPIを用いる必要がある。
- APIは審査基準が厳しい
- 審査通るまではSANDBOXモードで動作し、10ユーザーの新着20件までの情報しか取得できない
- SANDBOXモードで取得するユーザーは個別に許可をもらう必要がある
- APIの利用はURL ENDPOINTにアクセスすることでJSON形式でデータを取得することができるREST APIなので実装は難しくない
- usernameとuseridはことなり、APIで利用するのはuserid。(APIを用いてusernameからuseridを取得する必要あり。ここを理解していなくてハマった。)
- APIの利用にはアクセストークンが必要。これは、管理画面で発行されるClient IDともClient Secretとも違い、Client IDを用いて別途取得する必要がある。(セッションごとに必要なものではなく、一度取得すればリセットしないかぎり使える)
- 2015年10月17日からAPIの審査が必要になったらしい。なので、この日付より古いネットの情報は注意が必要
事前準備
- Developer登録
https://www.instagram.com/developer/
から開発者情報を入力 - Applicationの登録
Detailsタブ
Valid redirect URIs:
アクセストークンを取得するのに利用。今回の用途では実在するURLであればひとまずなんでも良いSecurityタブ
Disable implicit OAuth:チェックを外す
Enforce signed requests:チェックを外す - ApplicationごとのClient IDが発行されるのでメモします
- Sandboxユーザーの追加
Manage Clients – EDIT – Sandbox
で写真を取得したいユーザーを追加します。
追加したユーザーには個別に承認を貰う必要があります。 - アクセストークンの取得
APIを利用する際に必要なAccess Tokenを取得します。
・Application登録時に設定したRedirect URL
・取得したClient ID
を下記URLに含めてブラウザからアクセスします。
1https://www.instagram.com/oauth/authorize/?response_type=token&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URL}
認証を求められるのでAuthorizeをクリック
ブラウザのページがリダイレクトで指定したサイトにジャンプします。
その際、ブラウザのアドレスバーのURLに表示されるaccess_token以降の文字列がアクセストークンになります。 - 情報を取得したいユーザーのuseridを取得
繰り返しになりますが、SANDBOXモードでは写真や情報を取得するユーザーには個別に許可を貰う必要があります。またAPIではusernameではなくuseridを利用する必要があるため、対象ユーザーのuseridを取得します。
usernameとはhttps://www.instagram.com/kyarykyary0129/ のkyarykyary0129の部分です。下記URLでUSERNAMEとACCESS_TOKENを指定してブラウザでアクセス
1<span style="color: #000000;">https://api.instagram.com/v1/users/search?q={USERNAME}&access_token={ACCESS_TOKEN}</span>
ブラウザにUSERNAMEで指定したユーザーの情報が表示されます。(見やすく整形しています)
123456789101112131415{"data": [{"bio": "","full_name": "jun kawasaki","id": "4159593","profile_picture": "https://scontent.cdninstagram.com/t51.2885-19/s150x150/12816775_1001839336556997_1168307022_a.jpg","username": "jun784","website": "http://junkawasaki.me"}],"meta": {"code": 200}}
上記の場合、useridは4159593になります。
写真投稿の取得
ここまでの事前準備で取得した
・アクセストークン
・取得対象ユーザーのuserid
をAPIで利用して情報をとります
指定ユーザーの新着情報取得
1 |
https://api.instagram.com/v1/users/{user-id}/media/recent/?access_token={ACCESS-TOKEN} |
Instagramの投稿写真を取得するためのコードを作成したので公開しておきます。写真一覧取るだけのシンプルなものです。今後これをベースに機能追加予定。
MiniJSON及びJsonNodeをダウンロードしておくこと。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
using UnityEngine; using System; using System.IO; using System.Net; using System.Text; using System.Net.Security; using System.Security.Cryptography.X509Certificates; using System.Collections.Generic; using System.Linq; //Unity C#でJSONの扱い方 //http://qiita.com/phi/items/914bc839b543988fc0ec //http://qiita.com/asus4/items/bac121c34cd3169116c0 using MiniJSON; //Also Download JsonNode public class InstagramApi : MonoBehaviour { public string access_token; public string username; public GameObject[] PhotoFrames; public InstagramApi(string access_token) { this.access_token = access_token; } void Start() { StartCoroutine("MainRoutine"); } /// <summary> /// 設定された情報を元にインスタグラムにアクセスしてフォトフレームを書き換えます /// </summary> private IEnumerator<bool> MainRoutine() { //未設定チェック if (username == "") { Debug.Log("username is not set");return null; } if (access_token == "") { Debug.Log("access token is not set"); return null; } if (PhotoFrames.Length==0) { Debug.Log("PhotoFrames is not set"); return null; } //メイン処理 var userid = getUseridFomUsername(username); var photoURLs = getRecentPhotos(userid); for (int i = 0; i < PhotoFrames.Length; i++) { if (i >= photoURLs.Length) { break; } StartCoroutine(attacheWebImageToGameobject(photoURLs[i], PhotoFrames[i])); } return null; } /// <summary> /// InstagramユーザーネームからユーザーIDを取得する関数 /// </summary> /// <param name="username">ユーザーネーム</param> /// <returns></returns> public string getUseridFomUsername(string username) { string API_URI = "https://api.instagram.com/v1/users/search?q={USERNAME}&access_token={ACCESS_TOKEN}"; API_URI = API_URI.Replace("{USERNAME}", username); API_URI = API_URI.Replace("{ACCESS_TOKEN}", this.access_token); var jsonText = getHtml(API_URI); var json = JsonNode.Parse(jsonText); var id = json["data"][0]["id"].Get<string>(); return (id); } /// <summary> /// 指定のユーザーの最新投稿写真のURLを配列で取得します。動画の場合はサムネイル画像になります。 /// </summary> /// <param name="userid"></param> /// <param name="count"></param> /// <returns></returns> public string[] getRecentPhotos(string userid, int count = 20) { List<string>PhotoURLs= new List<string>(); string API_URI = "https://api.instagram.com/v1/users/{USERID}/media/recent/?access_token={ACCESS_TOKEN}&count={COUNT}"; API_URI = API_URI.Replace("{USERID}", userid); API_URI = API_URI.Replace("{ACCESS_TOKEN}", this.access_token); API_URI = API_URI.Replace("{COUNT}", count.ToString()); var jsonText = getHtml(API_URI); var json = JsonNode.Parse(jsonText); var data = json["data"]; foreach(var d in data) { var PhotoURL = d["images"]["standard_resolution"]["url"].Get<string>(); PhotoURLs.Add(PhotoURL); } return (PhotoURLs.ToArray()); } /// <summary> /// //指定したウェブ画像を読み込んでゲームオブジェクトのテクスチャとして表示 /// 呼び出し方:StartCoroutine(attacheWebImageToGameobject(PhotoURL, Gameobject)); /// </summary> /// <param name="url"></param> /// <param name="gObj"></param> /// <returns></returns> private IEnumerator<WWW> attacheWebImageToGameobject(string url, GameObject gObj) { WWW texturewww = new WWW(url); yield return texturewww; gObj.GetComponent<Renderer>().material.mainTexture = texturewww.texture; } /// <summary> /// HTMLの取得関数(SSLエラー対処済み) /// </summary> /// <param name="URL"></param> /// <returns></returns> private string getHtml(string URL) { SSLValidator.OverrideValidation();//Avoid SSL error WebClient wc = new WebClient(); Stream st = wc.OpenRead(URL); Encoding enc = Encoding.GetEncoding("utf-8"); StreamReader sr = new StreamReader(st, enc); string html = sr.ReadToEnd(); sr.Close(); st.Close(); return (html); } } //Avoid SSL error //http://stackoverflow.com/questions/18454292/system-net-certificatepolicy-to-servercertificatevalidationcallback-accept-all-c public static class SSLValidator { private static bool OnValidateCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; } public static void OverrideValidation() { ServicePointManager.ServerCertificateValidationCallback = OnValidateCertificate; ServicePointManager.Expect100Continue = true; } } //【Unity】指定したゲームオブジェクトから名前で子オブジェクトを検索する拡張メソッド //http://baba-s.hatenablog.com/entry/2014/08/01/101104 public static class GameObjectExtensions { /// <summary> /// 深い階層まで子オブジェクトを名前で検索して GameObject 型で取得します /// </summary> /// <param name="self">GameObject 型のインスタンス</param> /// <param name="name">検索するオブジェクトの名前</param> /// <param name="includeInactive">非アクティブなオブジェクトも検索する場合 true</param> /// <returns>子オブジェクト</returns> public static GameObject FindDeep( this GameObject self, string name, bool includeInactive = false) { var children = self.GetComponentsInChildren<Transform>(includeInactive); foreach (var transform in children) { if (transform.name == name) { return transform.gameObject; } } return null; } } |