Last active
September 4, 2022 02:59
-
-
Save 19h/2824e50d9a3bac75b6f49fc7b9d88dd7 to your computer and use it in GitHub Desktop.
Instagram following followers network graph dumper crawler spider node.js api / private api
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { IgApiClient, IgLoginTwoFactorRequiredError } = require('instagram-private-api'); | |
const inquirer = require('inquirer'); | |
const Bluebird = require('bluebird'); | |
const fs = require('fs'); | |
process.env.IG_USERNAME = 'xxx'; | |
process.env.IG_PASSWORD = 'xxx'; | |
const ig = new IgApiClient(); | |
ig.state.generateDevice(process.env.IG_USERNAME); | |
ig.state.deserialize( | |
fs | |
.readFileSync('./state.json') | |
.toString(), | |
); | |
const waitInSeconds = (seconds) => { | |
return new Promise(resolve => { | |
setTimeout(() => { | |
resolve(); | |
}, seconds * 1000); | |
}); | |
}; | |
async function getFollowers( | |
username, | |
ig, | |
opts = {}, | |
) { | |
const { delay, limit } = opts; | |
const id = await ig.user.getIdByUsername(username); | |
const followersFeed = await ig.feed.accountFollowing(id); | |
let followers = []; | |
let reqId = 0; | |
do { | |
reqId += 1; | |
console.log(`Requesting followers (iter: ${reqId}) for ${username}...`); | |
const items = await followersFeed.items(); | |
followers = [...followers, ...items]; | |
if (limit && limit !== -1) { | |
if (followers.length >= limit) { | |
break; | |
} | |
} | |
await waitInSeconds(delay); | |
} while (followersFeed.isMoreAvailable()); | |
return followers; | |
} | |
(async () => { | |
/*await ig.simulate.preLoginFlow(); | |
const loggedInUser = | |
await Bluebird.try(() => ig.account.login(process.env.IG_USERNAME, process.env.IG_PASSWORD)).catch( | |
IgLoginTwoFactorRequiredError, | |
async err => { | |
const { username, totp_two_factor_on, two_factor_identifier } = err.response.body.two_factor_info; | |
// decide which method to use | |
const verificationMethod = totp_two_factor_on ? '0' : '1'; // default to 1 for SMS | |
// At this point a code should have been sent | |
// Get the code | |
const { code } = await inquirer.prompt([ | |
{ | |
type: 'input', | |
name: 'code', | |
message: `Enter code received via ${verificationMethod === '1' ? 'SMS' : 'TOTP'}`, | |
}, | |
]); | |
// Use the code to finish the login process | |
return ig.account.twoFactorLogin({ | |
username, | |
verificationCode: code, | |
twoFactorIdentifier: two_factor_identifier, | |
verificationMethod, // '1' = SMS (default), '0' = TOTP (google auth for example) | |
trustThisDevice: '1', // Can be omitted as '1' is used by default | |
}); | |
}); | |
process.nextTick(async () => await ig.simulate.postLoginFlow().catch(() => {}));*/ | |
ig.state.serialize().then(data => require('fs').writeFileSync('./state.json', JSON.stringify(data))); | |
const me_id = await ig.user.getIdByUsername('in19h'); | |
const me_following = await getFollowers('in19h', ig); | |
console.log("Found %s following", me_following.length); | |
const other_names = | |
me_following.map(f => f.username); | |
const others = new Map(); | |
const others_id = new Map(); | |
for (const [i, other_name] of other_names.entries()) { | |
console.log(`Processing ${other_name} (${i} of ${other_names.length})...`); | |
try { | |
const user_rel = | |
JSON.parse( | |
fs.readFileSync(`./following/${other_name}.json`) | |
.toString(), | |
); | |
others_id.set(user_rel.id, other_name); | |
others.set(user_rel.id, user_rel.followers); | |
} catch { | |
const followers = | |
await getFollowers( | |
other_name, | |
ig, | |
{ | |
delay: 0, | |
limit: 50, | |
}, | |
); | |
const other_id = await ig.user.getIdByUsername(other_name); | |
others_id.set(other_id, other_name); | |
others.set(other_id, followers); | |
fs.writeFileSync( | |
`./following/${other_name}.json`, | |
JSON.stringify( | |
{ | |
id: other_id, | |
followers | |
}, | |
undefined, | |
4, | |
), | |
); | |
} | |
} | |
const reciprocals = new Map(); | |
for (const [other_id, following] of Array.from(others)) { | |
for (const user of following) { | |
const reciprocal = reciprocals.get(user.pk) || []; | |
reciprocal.push(`"${others_id.get(other_id)} (${other_id})" -> "${user.username} (${user.pk})"`) | |
reciprocals.set(user.pk, reciprocal); | |
} | |
} | |
const out = new Set(); | |
for (const user of me_following) { | |
if (reciprocals.has(user.pk)) { | |
console.log(`Found reciprocal for ${user.username} (${user.pk}), followed by ${reciprocals.get(user.pk).length} users..`); | |
out.add(`"in19h (${me_id})" -> "${user.username} (${user.pk})";`); | |
for (const reciprocal of reciprocals.get(user.pk)) { | |
out.add(reciprocal); | |
} | |
} | |
} | |
const dot = `digraph G { | |
rankdir = LR; | |
${Array.from(out).join('\n')} | |
}`; | |
fs.writeFileSync('graph.dot', dot); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment