[Golang] Get Photos and Videos in Instagram Post
Interesting small program to get URL of all photos and videos in Instagram post.
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.
Given the URL of the post as follows:
https://www.instagram.com/p/BfJzG64BZVY/
The code of the post is BfJzG64BZVY. We will use the code as one of the arguments in our func call.
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 | package igmedia import ( "encoding/json" "errors" "fmt" "io/ioutil" "net/http" "net/url" "strconv" "strings" "time" ) const urlPost = `https://www.instagram.com/p/{{CODE}}/?__a=1` const userAgent = "Instagram 10.3.2 (iPhone7,2; iPhone OS 9_3_3; en_US; en-US; scale=2.00; 750x1334) AppleWebKit/420+" type postInfo struct { GraphQL struct { ShortcodeMedia EdgeMedia `json:"shortcode_media"` } `json:"graphql"` } type EdgeMedia struct { Typename string `json:"__typename"` Shortcode string `json:"shortcode"` Dimensions struct { Height int64 `json:"height"` Width int64 `json:"width"` } `json:"dimensions"` DisplayUrl string `json:"display_url"` DisplayResources []struct { Src string `json:"src"` ConfigWidth int64 `json:"config_width"` ConfigHeight int64 `json:"config_height"` } `json:"display_resources"` VideoUrl string `json:"video_url"` IsVideo bool `json:"is_video"` TakenAtTimestamp int64 `json:"taken_at_timestamp"` Location struct { Id string `json:"id"` HasPublicPage bool `json:"has_public_page"` Name string `json:"name"` Slug string `json:"slug"` } `json:"location"` EdgeSidecarToChildren struct { Edges []struct { Node EdgeMedia `json:"node"` } `json:"edges"` } `json:"edge_sidecar_to_children"` } // return URL of image with best resolution func (em *EdgeMedia) getImageUrl() string { res := em.DisplayResources return res[len(res)-1].Src } func (em *EdgeMedia) getVideoUrl() string { return em.VideoUrl } func (em *EdgeMedia) printEdgeMediaChildInfo() { indentation := " " fmt.Println(indentation + em.Typename) switch em.Typename { case "GraphImage": fmt.Println(indentation + em.getImageUrl()) case "GraphVideo": fmt.Println(indentation + em.getVideoUrl()) default: panic(em.Typename) } fmt.Println("") } func (em *EdgeMedia) printEdgeMediaInfo() { fmt.Println(em.Typename) fmt.Println(stripQueryString(codeToUrl(em.Shortcode))) // print media (photos and videos) links switch em.Typename { case "GraphImage": fmt.Println(em.getImageUrl()) case "GraphVideo": fmt.Println(em.getVideoUrl()) case "GraphSidecar": fmt.Println("") for _, edge := range em.EdgeSidecarToChildren.Edges { edge.Node.printEdgeMediaChildInfo() } default: panic(em.Typename) } printTimestamp(em.TakenAtTimestamp) fmt.Println("") } // Given the code of the post, return url of the post. func codeToUrl(code string) string { return strings.Replace(urlPost, "{{CODE}}", code, 1) } func printTimestamp(timestamp int64) { fmt.Println(formatTimestamp(timestamp)) } func formatTimestamp(timestamp int64) string { t := time.Unix(timestamp, 0) return t.Format(time.RFC3339) } // Remove query string in the URL func stripQueryString(inputUrl string) string { u, err := url.Parse(inputUrl) if err != nil { panic(err) } u.RawQuery = "" return u.String() } // Send HTTP request and get http response on behalf of a specific Instagram // user. After login to Instagram, you can get the cookies of *ds_user_id*, // *sessionid*, *csrftoken* in Chrome Developer Tools. // See https://stackoverflow.com/a/44773079 // or // https://github.com/hoschiCZ/instastories-backup#obtain-cookies func getHTTPResponse(url, ds_user_id, sessionid, csrftoken string) (b []byte, 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", userAgent) 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 } return ioutil.ReadAll(resp.Body) } // Given code of post, return information of the post. func GetPostInfo(code, ds_user_id, sessionid, csrftoken string) (em EdgeMedia, err error) { url := codeToUrl(code) b, err := getHTTPResponse(url, ds_user_id, sessionid, csrftoken) if err != nil { return } pi := postInfo{} err = json.Unmarshal(b, &pi) if err != nil { return } em = pi.GraphQL.ShortcodeMedia return } |
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | package igmedia import ( "os" "testing" ) func ExampleGetPostInfo(t *testing.T) { em, err := GetPostInfo(os.Getenv("IG_TEST_CODE"), os.Getenv("IG_DS_USER_ID"), os.Getenv("IG_SESSIONID"), os.Getenv("IG_CSRFTOKEN")) if err != nil { t.Error(err) return } em.printEdgeMediaInfo() } |
The full code is also available on my GitHub repo [1].
Tested on: Ubuntu Linux 17.10, Go 1.9.4.
References:
[1] | GitHub - siongui/goigmedia: Get links of Instagram user media (photos and videos) in Go. |