- type: say
message: >-
💡 First, search and filter for the people you're interested in. Then, run
this command on the search results page to extract their data.
- type: ask
param: targetProfileCount
message: How many LinkedIn profiles would you like to extract?
options:
- label: 👤100
value: 100
- label: 👥1k
value: 1000
- $custom
default: ''
vision:
enabled: false
mode: area
send: true
hint: ''
optionsInvalid: false
- type: js
code: |
async function scrollAndCollectProfiles(targetProfileCount) {
const config = {
scrollDelay: 2000,
maxRetries: 3,
selectors: {
nextButton: '.artdeco-pagination--has-controls .artdeco-button:nth-of-type(2)',
profileList: '[role="list"]',
profileContainer: 'li',
name: 'span[aria-hidden="true"]',
status: '.t-14.t-black.t-normal',
link: 'a[data-test-app-aware-link]'
}
};
const profiles = [];
const uniqueProfileLinks = new Set();
// Function to scroll down the page with a delay
const scrollAndWait = () => new Promise(resolve => {
window.scrollTo(0, document.body.scrollHeight);
setTimeout(resolve, config.scrollDelay);
});
// Function to extract profiles from the page
const extractCurrentProfiles = () => {
const containers = document.querySelectorAll(`${config.selectors.profileList} ${config.selectors.profileContainer}`);
let newProfilesFound = false;
containers.forEach(container => {
try {
const fullLink = container.querySelector(config.selectors.link).href;
const link = fullLink.split('?')[0];
if (!uniqueProfileLinks.has(link)) {
const name = container.querySelector(config.selectors.name)?.textContent.trim() || 'No name';
const status = container.querySelector(config.selectors.status)?.textContent.trim() || 'No status';
profiles.push({ name, status, link });
uniqueProfileLinks.add(link);
newProfilesFound = true;
}
} catch (error) {
console.log('Error processing profile:', error); // Logging errors
}
});
return newProfilesFound;
};
// Main loop to collect profiles until target is reached
let retries = 0;
while (profiles.length < targetProfileCount && retries < config.maxRetries) {
const newProfilesFound = extractCurrentProfiles();
retries = (profiles.length < targetProfileCount && !newProfilesFound) ? retries + 1 : 0;
await scrollAndWait();
const nextButton = document.querySelector(config.selectors.nextButton);
if (nextButton && !nextButton.disabled) {
nextButton.click();
await scrollAndWait();
} else if (!newProfilesFound) {
break; // Exit if no new profiles found
}
}
// Trim excess profiles if collected more than target count
profiles.length = Math.min(profiles.length, targetProfileCount); // Keep only up to target count
console.log(`Found ${profiles.length} profiles out of ${targetProfileCount} requested`);
return profiles; // Return the collected profiles
}
return scrollAndCollectProfiles(targetProfileCount);
param: json
timeout: 300000
args: targetProfileCount
silent: true
- type: say
message: |-
**Extracted:**
{{json}}
- param: action
options:
- label: ✅ DONE
value: done
- label: 📦 EXPORT JSON
value: export
vision:
enabled: false
mode: area
hint: ''
send: true
type: ask
message: ''
default: ''
optionsInvalid: false
- type: stop
condition: '{{action}} = done'
- what: param
filename: linkedin-group-members.txt
condition: '{{action}} = export'
type: export
param: json
All rights reserved © HARPA AI TECHNOLOGIES LLC, 2021 — 2025
Designed and engineered in Finland 🇫🇮