[Golang] Get Instagram Following and Followers


Interesting small program to get the JSON format data of following and followers of a specific Instagram user.

The procedure of reading JSON data is the same as the Instagram story API [1]. Please read the post if you are not familiar with the API.

In this program only Go standard library is used, no third-party packages.

To access the Instagram API via local Go program, you need to login Instagram and get the following information from your browser:

  • ds_user_id
  • sessionid
  • csrftoken

Please see this SO answer to get above values on Chrome browser.

ds_user_id sessionid csrftoken

Moreover, you need to know the user id of the specific user, please read my previous post to get the id of the user. [3]

After you get the values, you can get the JSON response from the following code:

package igfollow

import (
      "encoding/json"
      "errors"
      "net/http"
      "strconv"
      "strings"
)

const UrlFollowers = `https://i.instagram.com/api/v1/friendships/{{USERID}}/followers/`
const UrlFollowing = `https://i.instagram.com/api/v1/friendships/{{USERID}}/following/`

type RawFollow struct {
      Users     []FollowUser `json:"users"`
      BigList   bool         `json:"big_list"` // if false, no next_max_id in response
      PageSize  int64        `json:"page_size"`
      Status    string       `json:"status"`
      NextMaxId string       `json:"next_max_id"` // used for pagination if list is too big
}

type FollowUser struct {
      Pk       int64  `json:"pk"`
      Username string `json:"username"`
}

// id: Id of the Instagram user whose followers to be retrieved.
//
// ds_user_id, sessionid, csrftoken: Login Instagram and get these three cookie
// values from Chrome Developer Tools. See https://stackoverflow.com/a/44773079
func GetFollowers(id, ds_user_id, sessionid, csrftoken string) (rf RawFollow, err error) {
      url := strings.Replace(UrlFollowers, "{{USERID}}", id, 1)
      rf, err = GetFollowResponse(url, ds_user_id, sessionid, csrftoken)
      if err != nil {
              return
      }

      // If the list is too big and next_max_id is not ""
      for rf.NextMaxId != "" {
              urln := url + "?max_id=" + rf.NextMaxId
              rfn, err := GetFollowResponse(urln, ds_user_id, sessionid, csrftoken)
              if err != nil {
                      return rf, err
              }
              rf.Users = append(rf.Users, rfn.Users...)
              rf.NextMaxId = rfn.NextMaxId
      }
      return
}

// id: Id of the Instagram user whose following to be retrieved.
//
// ds_user_id, sessionid, csrftoken: Login Instagram and get these three cookie
// values from Chrome Developer Tools. See https://stackoverflow.com/a/44773079
func GetFollowing(id, ds_user_id, sessionid, csrftoken string) (rf RawFollow, err error) {
      url := strings.Replace(UrlFollowing, "{{USERID}}", id, 1)
      rf, err = GetFollowResponse(url, ds_user_id, sessionid, csrftoken)
      if err != nil {
              return
      }

      // If the list is too big and next_max_id is not ""
      for rf.NextMaxId != "" {
              urln := url + "?max_id=" + rf.NextMaxId
              rfn, err := GetFollowResponse(urln, ds_user_id, sessionid, csrftoken)
              if err != nil {
                      return rf, err
              }
              rf.Users = append(rf.Users, rfn.Users...)
              rf.NextMaxId = rfn.NextMaxId
      }
      return
}

func GetFollowResponse(url, ds_user_id, sessionid, csrftoken string) (rf RawFollow, err error) {
      req, err := http.NewRequest("GET", url, nil)
      if err != nil {
              return
      }

      req.AddCookie(&http.Cookie{Name: "ds_user_id", Value: ds_user_id})
      req.AddCookie(&http.Cookie{Name: "sessionid", Value: sessionid})
      req.AddCookie(&http.Cookie{Name: "csrftoken", Value: csrftoken})

      req.Header.Set("User-Agent", "Instagram 10.3.2 (iPhone7,2; iPhone OS 9_3_3; en_US; en-US; scale=2.00; 750x1334) AppleWebKit/420+")

      client := &http.Client{}
      resp, err := client.Do(req)
      if err != nil {
              return
      }
      defer resp.Body.Close()

      if resp.StatusCode != 200 {
              err = errors.New("resp.StatusCode: " + strconv.Itoa(resp.StatusCode))
              return
      }

      dec := json.NewDecoder(resp.Body)
      err = dec.Decode(&rf)
      return
}

Example:

package igfollow

import (
      "os"
      "testing"
)

func ExampleGetFollowing(t *testing.T) {
      rf, err := GetFollowing(
              os.Getenv("IG_TEST_USER_ID"),
              os.Getenv("IG_DS_USER_ID"),
              os.Getenv("IG_SESSIONID"),
              os.Getenv("IG_CSRFTOKEN"))
      if err != nil {
              t.Error(err)
              return
      }
      t.Log(rf)
      t.Log(len(rf.Users))
}

func ExampleGetFollowers(t *testing.T) {
      rf, err := GetFollowers(
              os.Getenv("IG_TEST_USER_ID"),
              os.Getenv("IG_DS_USER_ID"),
              os.Getenv("IG_SESSIONID"),
              os.Getenv("IG_CSRFTOKEN"))
      if err != nil {
              t.Error(err)
              return
      }
      t.Log(rf)
      t.Log(len(rf.Users))
}

The full code is also available on my GitHub repo [2].


Tested on: Ubuntu Linux 17.10, Go 1.9.4.


References:

[1]Chrome IG Story — Bribing the Instagram Story API with cookies 🍪🍪🍪
[2]GitHub - siongui/goigfollow: Get Instagram following and followers in Go
[3][Golang] Get Instagram User ID