├── .env.example
├── .gitignore
├── LICENSE
├── README.md
├── __tests__
└── index.js
├── instagram.js
├── package-lock.json
└── package.json
/.env.example:
--------------------------------------------------------------------------------
1 | USERNAME=ig_username
2 | PASSWORD=ig_password
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .env
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Alex
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # instagram-nodejs
2 | Auth and get followers on instagram with nodejs
3 |
4 | Join us with gitter: https://gitter.im/nodejs-instagram/Library
5 |
6 | ### Important : you must update csrf token and sessionId only if password was changed
7 |
8 | ### To install from npm repository (I recommended use yarn, but you can use npm):
9 | ```
10 | yarn add instagram-nodejs-without-api
11 | ```
12 |
13 | ### You can get instagram followers with next code:
14 | ```js
15 | let Instagram = require('instagram-nodejs-without-api');
16 | Instagram = new Instagram()
17 |
18 |
19 | Instagram.getCsrfToken().then((csrf) =>
20 | {
21 | Instagram.csrfToken = csrf;
22 | }).then(() =>
23 | {
24 | return Instagram.auth('inst-your-username', 'inst-your-password').then(sessionId =>
25 | {
26 | Instagram.sessionId = sessionId
27 |
28 | return Instagram.getUserDataByUsername('username-for-get').then((t) =>
29 | {
30 | return Instagram.getUserFollowers(t.graphql.user.id).then((t) =>
31 | {
32 | console.log(t); // - instagram followers for user "username-for-get"
33 | })
34 | })
35 |
36 | })
37 | }).catch(console.error);
38 | ```
39 |
40 | ### Follow/unfollow
41 | ```js
42 | Inst = new Instagram()
43 |
44 | Inst.csrfToken = 'your-csrf'
45 | Inst.sessionId = 'your-session-id'
46 | Inst.follow(3,0) //follow "kevin"
47 | Inst.follow(3, 1) //unfollow "kevin"
48 | ````
49 |
50 | ### Like/unlike
51 | ````js
52 | //get media id by url and like
53 | Insta.getMediaIdByUrl('https://www.instagram.com/p/BT1ynUvhvaR/').then(r => Insta.like(r).then(d => console.log(d)))
54 | //get media id by url and unlike
55 | Insta.getMediaIdByUrl('https://www.instagram.com/p/BT1ynUvhvaR/').then(r => Insta.unlike(r).then(d => console.log(d)))
56 | ````
57 |
58 | ### Get feed
59 | ````js
60 | let pageFirst = Insta.getFeed(10).then(function(t)
61 | {
62 | let PageSecond = Insta.getFeed(10, Insta.getFeedNextPage(t)).then(function(t)
63 | {
64 | //two page
65 | console.log(t)
66 | })
67 | })
68 | ````
69 |
70 | ### Get user media
71 | ````js
72 | //... auth (look up)
73 | //for example: get 12 first media entries for "kevin"
74 | // 0 - if you need to get first page
75 | // next cursor : r.page_info.end_cursor
76 | Insta.getUserMedia(3, '0', 12).then(f => console.log(f))
77 | ````
78 |
79 | ### Get media by hashtags and locations
80 | ````js
81 | Insta.commonSearch('Kyiv').then(r =>
82 | {
83 | //get location id for Kyiv
84 | let locationId = r.places[0].place.location['pk']
85 | //search posts from Kyiv
86 | Insta.searchBy('location', locationId, '0', 12).then(r => console.log(r))
87 | })
88 | //search posts by hashtag "Eurovision"
89 | Insta.searchBy('hashtag', 'Eurovision').then(r => console.log(r))
90 | ````
91 |
92 | When you pass items counter param instagram create pagination tokens on all iterations and gives on every response end_cursor, which the need to pass on next feed request
93 |
94 |
95 | You can get user id with Inst.getUserDataByUsername() method
96 |
97 | Star this repository on github, please. Thank you
98 |
99 |
100 | ### Tests
101 |
102 | You must define a .env file with username and password of the instagram login. (see .env.example)
103 |
104 | ``` npm test ```
105 |
106 | ``` yarn test ```
--------------------------------------------------------------------------------
/__tests__/index.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config()
2 | const test = require('ava');
3 |
4 |
5 | const username = process.env.USERNAME;
6 | const password = process.env.PASSWORD;
7 |
8 | console.log(username, password);
9 |
10 | test('user exist', t => {
11 | t.true(Boolean(username));
12 | });
13 |
14 | test('password exist', t => {
15 | t.true(Boolean(password));
16 | });
17 |
18 | test('Get Instagram Account', async t => {
19 | const InstagraApi = require('../instagram.js');
20 | const Instagram = new InstagraApi();
21 |
22 | Instagram.csrfToken = await Instagram.getCsrfToken();
23 | Instagram.sessionId = await Instagram.auth(username, password);
24 |
25 | const data = await Instagram.getUserDataByUsername('getnerdify');
26 | const userId = data.graphql.user.id;
27 |
28 | t.is(userId, '7696780203');
29 | });
30 |
--------------------------------------------------------------------------------
/instagram.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | "use-strict";
4 |
5 | const fetch = require('node-fetch');
6 | const formData = require('form-data');
7 |
8 | module.exports = class Instagram {
9 | /**
10 | * Constructor
11 | */
12 | constructor(csrfToken, sessionId) {
13 | this.csrfToken = csrfToken
14 | this.sessionId = sessionId
15 | this.userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
16 | this.userIdFollowers = {};
17 | this.timeoutForCounter = 250
18 | this.timeoutForCounterValue = 20000
19 | this.paginationDelay = 20000
20 | this.receivePromises = {}
21 | this.searchTypes = ['location', 'hashtag']
22 |
23 | this.essentialValues = {
24 | sessionid : undefined,
25 | ds_user_id : undefined,
26 | csrftoken : undefined,
27 | shbid : undefined,
28 | rur : undefined,
29 | mid : undefined,
30 | shbts : undefined,
31 | mcd : undefined,
32 | ig_cb : 1,
33 | //urlgen : undefined //this needs to be filled in according to my RE
34 | };
35 |
36 | this.baseHeader = {
37 | 'accept-langauge': 'en-US;q=0.9,en;q=0.8,es;q=0.7',
38 | 'origin': 'https://www.instagram.com',
39 | 'referer': 'https://www.instagram.com/',
40 | 'upgrade-insecure-requests': '1',
41 | 'user-agent': this.userAgent,
42 | }
43 | }
44 |
45 |
46 | generateCookie(simple){
47 | if (simple) return 'ig_cb=1'
48 |
49 | var cookie = ''
50 | var keys = Object.keys(this.essentialValues)
51 | for (var i = 0; i < keys.length; i++){
52 | var key = keys[i];
53 | if (this.essentialValues[key] !== undefined) {
54 | cookie += key + '=' + this.essentialValues[key] + (i < keys.length - 1 ? '; ' : '')
55 | }
56 | }
57 |
58 | return cookie;
59 | }
60 |
61 | combineWithBaseHeader(data){
62 | return Object.assign(this.baseHeader, data)
63 | }
64 |
65 | updateEssentialValues(src, isHTML){
66 | //assumes that essential values will be extracted from a cookie unless specified by the isHTML bool
67 |
68 | if (!isHTML){
69 | var keys = Object.keys(this.essentialValues)
70 |
71 | for (var i = 0; i < keys.length; i++){
72 | var key = keys[i];
73 | if (!this.essentialValues[key])
74 | for (let cookie in src)
75 | if (src[cookie].includes(key) && !src[cookie].includes(key + '=""')){
76 | var cookieValue = src[cookie].split(';')[0].replace(key + '=', '')
77 | this.essentialValues[key] = cookieValue
78 | break;
79 | }
80 | }
81 | } else {
82 | var subStr = src;
83 |
84 | var startStr = '') - 1);
89 |
90 | var json = JSON.parse(subStr);
91 |
92 | this.essentialValues.csrftoken = json.config.csrf_token;
93 | this.rollout_hash = json.rollout_hash;
94 | }
95 | }
96 |
97 | /**
98 | * User data by username
99 | * @param {String} username
100 | * @return {Object} Promise
101 | */
102 | getUserDataByUsername(username) {
103 |
104 | var fetch_data = {
105 | 'method': 'get',
106 | 'headers':
107 | this.combineWithBaseHeader(
108 | {
109 | 'accept': 'text/html,application/xhtml+xml,application/xml;q0.9,image/webp,image/apng,*.*;q=0.8',
110 | 'accept-encoding': 'gzip, deflate, br',
111 | 'cookie': this.generateCookie()
112 | }
113 | )
114 | }
115 |
116 | return fetch('https://www.instagram.com/' + username, fetch_data).then(res => res.text().then(function (data) {
117 | const regex = /window\._sharedData = (.*);<\/script>/;
118 | const match = regex.exec(data);
119 |
120 | if (!match || (match && typeof match[1] === 'undefined')) {
121 | return '';
122 | }
123 |
124 | return JSON.parse(match[1]).entry_data.ProfilePage[0];
125 | }))
126 | }
127 |
128 | /**
129 | Is private check
130 | * @param {String} username
131 | */
132 | isPrivate(username) {
133 | return this.getUserDataByUsername(username).then((data) =>
134 | data.user.is_private
135 | )
136 | }
137 |
138 | /**
139 | * User followers list
140 | * Bench - 1k followers/1 min
141 | * @param {Int} userId
142 | * @param {String} endCursor cursor used to fetch next page
143 | * @param {Int} count count of results to return (API may return less)
144 | * @param {Int} followersCounter counter of followers
145 | * @param {Boolean} selfSelf if call by self
146 | * @return {Object} array followers list
147 | */
148 | getUserFollowers(userId, endCursor, count, followersCounter, selfSelf) {
149 | const self = this
150 |
151 | if (!selfSelf)
152 | self.userIdFollowers[userId] = []
153 |
154 | if (typeof self.receivePromises[userId] !== 'undefined' && !selfSelf)
155 | return 0
156 |
157 | count = count || 20;
158 |
159 | const query = {
160 | id: userId,
161 | include_reel: true,
162 | fetch_mutual: true,
163 | first: count
164 | };
165 | if (endCursor) {
166 | query.after = endCursor;
167 | }
168 |
169 | const variables = encodeURIComponent(JSON.stringify(query));
170 |
171 | self.receivePromises[userId] = 1
172 | return fetch('https://www.instagram.com/graphql/query/?query_hash=56066f031e6239f35a904ac20c9f37d9&variables=' + variables,
173 | {
174 | 'method': 'get',
175 | 'headers':
176 | this.combineWithBaseHeader(
177 | {
178 | 'accept': 'text/html,application/xhtml+xml,application/xml;q0.9,image/webp,image/apng,*.*;q=0.8',
179 | 'accept-encoding': 'gzip, deflate, br',
180 | 'cookie': this.generateCookie()
181 | }
182 | )
183 | }).then(res => {
184 | return res.text().then((response) => {
185 | //prepare convert to json
186 | let json = response;
187 |
188 | try {
189 | json = JSON.parse(response)
190 | }
191 | catch (e) {
192 | console.log('Session error')
193 | console.log(response)
194 | return [];
195 | }
196 |
197 | if (json.status == 'ok') {
198 | self.userIdFollowers[userId] = self.userIdFollowers[userId].concat(json.data.user.edge_followed_by.edges)
199 |
200 | if (json.data.user.edge_followed_by.page_info.has_next_page) {
201 | let end_cursor = json.data.user.edge_followed_by.page_info.end_cursor
202 | return new Promise((resolve) => {
203 | console.log('fetching next page in ' + this.paginationDelay / 1000 + ' seconds');
204 | setTimeout(() => {
205 | resolve(self.getUserFollowers(userId, end_cursor, count, 1, 1));
206 | }, this.paginationDelay);
207 | });
208 | }
209 | else {
210 | self.receivePromises[userId] = undefined
211 | return self.userIdFollowers[userId]
212 | }
213 |
214 | }
215 | else {
216 | return new Promise((resolve) => {
217 | console.log(json);
218 | console.log('request failed, retrying in ' + this.paginationDelay / 1000 + ' seconds');
219 | setTimeout(() => {
220 | resolve(self.getUserFollowers(userId, endCursor, count, followersCounter, selfSelf));
221 | }, this.paginationDelay);
222 | });
223 | }
224 |
225 | }).catch((e) => {
226 | console.log('Instagram returned:' + e)
227 | })
228 | })
229 | }
230 |
231 | /**
232 | * Get csrf token
233 | * @return {Object} Promise
234 | */
235 | getCsrfToken() {
236 | return fetch('https://www.instagram.com',
237 | {
238 | 'method': 'get',
239 | 'headers':
240 | this.combineWithBaseHeader(
241 | {
242 | 'accept': 'text/html,application/xhtml+xml,application/xml;q0.9,image/webp,image/apng,*.*;q=0.8',
243 | 'accept-encoding': 'gzip, deflate, br',
244 | 'cookie': this.generateCookie(true)
245 | }
246 | )
247 | }).then( t => {
248 | this.updateEssentialValues(t.headers._headers['set-cookie'])
249 | return t.text()
250 | }).then( html => {
251 | this.updateEssentialValues(html, true)
252 | return this.essentialValues.csrftoken
253 | }).catch(() =>
254 | console.log('Failed to get instagram csrf token')
255 | )
256 | }
257 |
258 | /**
259 | * Session id by usrname and password
260 | * @param {String} username
261 | * @param {String} password
262 | * @return {Object} Promise
263 | */
264 | auth(username, password) {
265 | var formdata = 'username=' + username + '&password=' + password + '&queryParams=%7B%7D'
266 |
267 | var options = {
268 | method : 'POST',
269 | body : formdata,
270 | headers :
271 | this.combineWithBaseHeader(
272 | {
273 | 'accept' : '*/*',
274 | 'accept-encoding' : 'gzip, deflate, br',
275 | 'content-length' : formdata.length,
276 | 'content-type' : 'application/x-www-form-urlencoded',
277 | 'cookie' : 'ig_cb=' + this.essentialValues.ig_cb,
278 | 'x-csrftoken' : this.csrfToken,
279 | 'x-instagram-ajax' : this.rollout_hash,
280 | 'x-requested-with' : 'XMLHttpRequest',
281 | }
282 | )
283 | }
284 |
285 | return fetch('https://www.instagram.com/accounts/login/ajax/', options).then(
286 | t => {
287 | this.updateEssentialValues(t.headers._headers['set-cookie'])
288 | return this.essentialValues.sessionid;
289 | }).catch(() =>
290 | console.log('Instagram authentication failed (challenge required erro)')
291 | )
292 | }
293 |
294 | /**
295 | * Registration for instagram, returning true or false
296 | * true if account was successfully created
297 | * @param {String} username
298 | * @param {String} password
299 | * @param {String} name
300 | * @param {String} email
301 | * @return {Boolen} account_created
302 | */
303 | reg(username, password, name, email) {
304 | let form = new formData();
305 | form.append('username', username)
306 | form.append('password', password)
307 | form.append('firstname', name)
308 | form.append('email', email)
309 | form.append('seamless_login_enabled', "1")
310 |
311 | return fetch('https://www.instagram.com/accounts/web_create_ajax/', {
312 | 'method': 'post',
313 | 'body': form,
314 | 'headers': {
315 | 'referer': 'https://www.instagram.com/',
316 | 'origin': 'https://www.instagram.com',
317 | 'user-agent': this.userAgent,
318 | 'x-instagram-ajax': '1',
319 | 'x-requested-with': 'XMLHttpRequest',
320 | 'x-csrftoken': this.csrfToken,
321 | cookie: 'csrftoken=' + this.csrfToken
322 | }
323 | })
324 | .then(res => res.json())
325 | .then(json => {
326 | return json.account_created;
327 | })
328 | .catch(() => console.log('Instagram registration failed'))
329 | }
330 |
331 |
332 | /**
333 | * I did not want to implement this, but I need a stars on github
334 | * If you use this library - star this rep https://github.com/yatsenkolesh/instagram-nodejs
335 | * Thank you, bro
336 | * Follow/unfollow user by id
337 | * @param {int} userID
338 | * @param {boolean} isUnfollow
339 | * @return {object} Promise of fetch request
340 | */
341 | follow(userId, isUnfollow) {
342 | const headers =
343 | {
344 | 'referer': 'https://www.instagram.com/',
345 | 'origin': 'https://www.instagram.com',
346 | 'user-agent': this.userAgent,
347 | 'x-instagram-ajax': '1',
348 | 'content-type': 'application/json',
349 | 'x-requested-with': 'XMLHttpRequest',
350 | 'x-csrftoken': undefined,
351 | cookie: ' sessionid=' + this.sessionId + '; csrftoken=' + this.csrfToken + '; mid=WPL0LQAEAAGG3XL5-xHXzClnpqA3; rur=ASH; mid=WRN1_AAEAAE07QksztCl3OCnLj8Y;'
352 | }
353 |
354 | return fetch('https://www.instagram.com/web/friendships/' + userId + (isUnfollow == 1 ? '/unfollow' : '/follow'),
355 | {
356 | 'method': 'post',
357 | 'headers': this.getHeaders()//headers
358 | }).then(res => {
359 | return res
360 | })
361 | }
362 |
363 | /**
364 | * @return {Object} default headers
365 | */
366 | getHeaders() {
367 | return {
368 | 'referer': 'https://www.instagram.com/p/BT1ynUvhvaR/?taken-by=yatsenkolesh',
369 | 'origin': 'https://www.instagram.com',
370 | 'user-agent': this.userAgent,
371 | 'x-instagram-ajax': '1',
372 | 'x-requested-with': 'XMLHttpRequest',
373 | 'x-csrftoken': this.csrfToken,
374 | cookie: ' sessionid=' + this.sessionId + '; csrftoken=' + this.csrfToken + ';'
375 | }
376 | }
377 |
378 | /**
379 | * Return user data by id
380 | * @param {Int} id
381 | * @return {Object} promise
382 | */
383 | getUserDataById(id) {
384 | let query = 'ig_user(' + id + '){id,username,external_url,full_name,profile_pic_url,biography,followed_by{count},follows{count},media{count},is_private,is_verified}'
385 |
386 | let form = new formData();
387 | form.append('q', query)
388 |
389 | return fetch('https://www.instagram.com/query/',
390 | {
391 | 'method': 'post',
392 | 'body': form,
393 | 'headers': this.getHeaders()
394 | }).then(res =>
395 | res.json().then(t => t)
396 | )
397 | }
398 |
399 | /**
400 | * When you pass items counter param instagram create pagination
401 | * tokens on all iterations and gives on every response end_cursor, which the need to pass on next feed request
402 | *
403 | * This method return first "items" posts of feed
404 | * Coming soon will be opportunity for get part of feed
405 | * On testing stage (+- all rights)
406 | * If you have a problems - create issue : https://github.com/yatsenkolesh/instagram-nodejs
407 | * @param {Int} items (default - 10)
408 | * @return {Object} Promise
409 | */
410 | getFeed(items, cursor) {
411 | items = items ? items : 10;
412 | return fetch('https://www.instagram.com/graphql/query/?query_id=17866917712078875&fetch_media_item_count=' + items + '&fetch_media_item_cursor=' + cursor + '&fetch_comment_count=4&fetch_like=10',
413 | {
414 | headers: this.getHeaders(),
415 | }).then(t =>
416 | t.json().then(r => r)
417 | )
418 | }
419 |
420 | /**
421 | * Simple variable for get next page
422 | * @param {Object} json contents from this.getFeed
423 | * @return {String} if next page is not exists - false
424 | */
425 | getFeedNextPage(json) {
426 | let page = json.data.user.edge_web_feed_timeline.page_info
427 |
428 | return page.has_next_page ? page.end_cursor : false
429 | }
430 |
431 | /**
432 | * Attention: postId need transfer only as String (reason int have max value - 2147483647)
433 | * @example postID - '1510335854710027921'
434 | * @param {String} post id
435 | * @return {Object} Promse
436 | */
437 | like(postId) {
438 | return fetch('https://www.instagram.com/web/likes/' + postId + '/like/',
439 | {
440 | 'method': 'POST',
441 | 'headers': this.getHeaders()
442 | }).then(t =>
443 | t.json().then(r => r)
444 | )
445 | }
446 |
447 | /**
448 | * Attention: postId need transfer only as String (reason int have max value - 2147483647)
449 | * @example postID - '1510335854710027921'
450 | * @param {String} postId
451 | * @return {Object} Promse
452 | */
453 | unlike(postId) {
454 | return fetch('https://www.instagram.com/web/likes/' + postId + '/unlike/',
455 | {
456 | 'method': 'POST',
457 | 'headers': this.getHeaders()
458 | }).then(t =>
459 | t.json().then(r => r)
460 | )
461 | }
462 |
463 |
464 | /**
465 | * @example url = https://www.instagram.com/p/BT1ynUvhvaR/
466 | * @param {String} url
467 | * @return {Object} Promise
468 | */
469 | getMediaInfoByUrl(url) {
470 | return fetch('https://api.instagram.com/oembed/?url=' + url,
471 | {
472 | 'headers': this.getHeaders()
473 | }).then(t => t.json().then(r => r))
474 | }
475 |
476 | /**
477 | * @example url = https://www.instagram.com/p/BT1ynUvhvaR/
478 | * @param {String} url
479 | * @return {Object} Promise
480 | */
481 | getMediaIdByUrl(url) {
482 | return this.getMediaInfoByUrl(url).then(t => t.media_id.split('_')[0])
483 | }
484 |
485 | /**
486 | * Get media user list on userId with pagination
487 | * @param {String} userId
488 | * @param {String} cursor (next cursor). Use 0, if you want to get first page
489 | * @param {Int} mediaCounter default - 12
490 | * @return {Object} Promise
491 | */
492 | getUserMedia(userId, cursor, mediaCounter) {
493 | cursor = cursor ? cursor : '0'
494 | mediaCounter = mediaCounter ? mediaCounter : 12
495 | let form = new formData()
496 | form.append('q', 'ig_user(' + userId + ') { media.after(' + cursor + ', ' + mediaCounter + ') {\
497 | count,\
498 | nodes {\
499 | __typename,\
500 | caption,\
501 | code,\
502 | comments {\
503 | count\
504 | },\
505 | comments_disabled,\
506 | date,\
507 | dimensions {\
508 | height,\
509 | width\
510 | },\
511 | display_src,\
512 | id,\
513 | is_video,\
514 | likes {\
515 | count\
516 | },\
517 | owner {\
518 | id\
519 | },\
520 | thumbnail_src,\
521 | video_views\
522 | },\
523 | page_info\
524 | }\
525 | }')
526 | form.append('ref', 'users::show')
527 | form.append('query_id', '17849115430193904') // this is static id. May be changed after rebuild, but now actually
528 |
529 | return fetch('https://www.instagram.com/query/',
530 | {
531 | headers: this.getHeaders(),
532 | method: 'post',
533 | body: form
534 | }).then(r => r.text().then(t => t))
535 | }
536 |
537 | /**
538 | * End cursor - t.entry_data.TagPage[0].tag.media.page_info['end_cursor']
539 | * Media(nodes) - t.entry_data.TagPage[0].tag.media['nodes']
540 | * @param {String} searchBy - location, hashtag
541 | * @param {String} q - location id, or hashtag
542 | * @param {String} cursor pagination cursor
543 | * @param {Int} mediaCounter
544 | * @return {Object} Promise
545 | */
546 | searchBy(searchBy, q, cursor, mediaCounter) {
547 | if (this.searchTypes.indexOf(searchBy) === false)
548 | throw 'search type ' + searchBy + ' is not found'
549 |
550 | //exclusion for hashtag if not cursor
551 | if (searchBy == 'hashtag' && !cursor) {
552 | return fetch('https://www.instagram.com/explore/tags/' + q + '/',
553 | {
554 | headers: this.getHeaders(),
555 | }).then(t => t.text().then(r => JSON.parse(r.match(/\