Skip to content

Instantly share code, notes, and snippets.

@Rikezenho
Last active October 19, 2024 03:19
Show Gist options
  • Save Rikezenho/02becf6a3a274c1dc476a0dee805da79 to your computer and use it in GitHub Desktop.
Save Rikezenho/02becf6a3a274c1dc476a0dee805da79 to your computer and use it in GitHub Desktop.
Script to retrieve the followings of an Instagram profile - run it on the profile page in DevTools console
(async function() {
// Check if we have cached results
if (window.instagramVerifiedFollowings) {
console.log("Using cached results");
displayResults(window.instagramVerifiedFollowings);
return;
}
function extractUserId() {
const scripts = document.getElementsByTagName('script');
for (const script of scripts) {
const match = script.textContent.match(/"user_id":"(\d+)"/);
if (match) {
return match[1];
}
}
throw new Error('Unable to find user ID. Make sure you\'re on an Instagram profile page and logged in.');
}
function getCSRFToken() {
const csrftoken = document.cookie.match(/csrftoken=([^;]+)/);
return csrftoken ? csrftoken[1] : null;
}
let fetchCount = 0;
let totalFollowings = 0;
async function fetchFollowings(userId, after = null, followings = []) {
try {
await new Promise(resolve => setTimeout(resolve, 10)); // 10ms delay
fetchCount++;
const variables = {
id: userId,
include_reel: true,
fetch_mutual: false,
first: 50,
after: after
};
const csrfToken = getCSRFToken();
if (!csrfToken) {
throw new Error('CSRF token not found. Make sure you\'re logged in.');
}
const response = await fetch(`/graphql/query/?query_hash=d04b0a864b4b54837c0d870b0e77e076&variables=${JSON.stringify(variables)}`, {
headers: {
'X-CSRFToken': csrfToken,
'X-Instagram-AJAX': '1',
'X-IG-App-ID': '936619743392459', // This is a common App ID for Instagram web
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
if (!data.data || !data.data.user || !data.data.user.edge_follow) {
throw new Error('Unexpected API response structure');
}
const edges = data.data.user.edge_follow.edges;
followings = followings.concat(edges);
const pageInfo = data.data.user.edge_follow.page_info;
totalFollowings = data.data.user.edge_follow.count;
console.log(`Fetch ${fetchCount} complete. Retrieved ${followings.length}/${totalFollowings} followings.`);
if (pageInfo.has_next_page) {
return fetchFollowings(userId, pageInfo.end_cursor, followings);
}
return followings;
} catch (error) {
console.error(`Error fetching followings: ${error.message}`);
return followings; // Return what we have so far
}
}
function displayResults(verifiedProfiles) {
const floatingElement = document.createElement('div');
floatingElement.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
width: 80vw;
max-width: 800px;
height: 80vh;
background-color: white;
border: 1px solid #ccc;
border-radius: 5px;
overflow-y: auto;
z-index: 9999;
padding: 10px;
font-family: Arial, sans-serif;
`;
// Add close button
const closeButton = document.createElement('button');
closeButton.innerHTML = '✖'; // X symbol
closeButton.style.cssText = `
color: #000;
position: absolute;
top: 5px;
right: 5px;
background: none;
border: none;
font-size: 20px;
cursor: pointer;
`;
closeButton.onclick = () => document.body.removeChild(floatingElement);
floatingElement.appendChild(closeButton);
// Add view controls
const controlsDiv = document.createElement('div');
controlsDiv.style.cssText = `
display: flex;
justify-content: center;
margin-bottom: 10px;
`;
const listViewButton = document.createElement('button');
listViewButton.textContent = 'List View';
listViewButton.style.marginRight = '10px';
const gridViewButton = document.createElement('button');
gridViewButton.textContent = 'Grid View';
controlsDiv.appendChild(listViewButton);
controlsDiv.appendChild(gridViewButton);
floatingElement.appendChild(controlsDiv);
// Create content container
const contentDiv = document.createElement('div');
floatingElement.appendChild(contentDiv);
function renderListView() {
contentDiv.innerHTML = '';
contentDiv.style.cssText = ''; // Reset any grid styles
verifiedProfiles.forEach(profile => {
const profileElement = document.createElement('div');
profileElement.style.cssText = `
display: flex;
align-items: center;
margin-bottom: 10px;
`;
profileElement.innerHTML = `
<img src="${profile.profilePic}" alt="${profile.username}" style="width: 50px; height: 50px; border-radius: 50%; margin-right: 10px;">
<a href="https://www.instagram.com/${profile.username}" target="_blank" style="text-decoration: none; color: black;">
<strong>${profile.username}</strong><br>
${profile.fullName}
</a>
`;
contentDiv.appendChild(profileElement);
});
}
function renderGridView() {
contentDiv.innerHTML = '';
contentDiv.style.cssText = `
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
justify-items: center;
padding: 10px;
`;
verifiedProfiles.forEach(profile => {
const profileElement = document.createElement('div');
profileElement.style.cssText = `
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
width: 100%;
`;
profileElement.innerHTML = `
<a href="https://www.instagram.com/${profile.username}" target="_blank" style="text-decoration: none; color: black; display: flex; flex-direction: column; align-items: center;">
<img src="${profile.profilePic}" alt="${profile.username}" style="width: 100px; height: 100px; border-radius: 50%; margin-bottom: 5px; object-fit: cover;">
<strong style="display: block; width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">${profile.username}</strong>
</a>
`;
contentDiv.appendChild(profileElement);
});
}
listViewButton.onclick = renderListView;
gridViewButton.onclick = renderGridView;
// Initial render
renderListView();
document.body.appendChild(floatingElement);
}
try {
const userId = extractUserId();
console.log("Extracted User ID:", userId);
const followings = await fetchFollowings(userId);
const verifiedProfiles = followings
.filter(edge => edge.node.is_verified)
.map(edge => ({
username: edge.node.username,
fullName: edge.node.full_name,
profilePic: edge.node.profile_pic_url
}))
.sort((a, b) => a.username.localeCompare(b.username));
// Cache the results
window.instagramVerifiedFollowings = verifiedProfiles;
console.log(`Found ${verifiedProfiles.length} verified profiles.`);
console.log(`Total API calls made: ${fetchCount}`);
displayResults(verifiedProfiles);
} catch (error) {
console.error('Fatal error:', error.message);
}
})();
@Rikezenho
Copy link
Author

Created entirely on Claude 3.5 Sonnet in 10 minutes!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment