Skip to content

Instantly share code, notes, and snippets.

@guillaumegarcia13
Last active December 1, 2020 09:40
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save guillaumegarcia13/1a41ad19a7035cbd7cb98f65b385b037 to your computer and use it in GitHub Desktop.
Save guillaumegarcia13/1a41ad19a7035cbd7cb98f65b385b037 to your computer and use it in GitHub Desktop.
Retrieve all LinkedIn profiles of people leaving a comment
/*====================================================================================================================
* Author: Guillaume GARCIA (https://www.linkedin.com/in/guillaumegarcia/)
* Date : 30-november-2020
*
* Usage
* -----
*
* Go to a LinkedIn post URL
* such as: https://www.linkedin.com/feed/update/urn:li:activity:6738104526265446400/
* Open Chrome DevTools
* Run this snippet
* Wait for it to complete (notification OR js alert)
* Paste to Excel all LinkedIn URL profiles
*====================================================================================================================*/
// Constants
const wait = 1500; // increase this in case you are dealing with post with VERY large volume of comments
const LINKEDIN_ICON = 'https://static-exp1.licdn.com/scds/common/u/images/logos/favicons/v1/favicon.ico';
// Helpers
const promiseSerializer = function(tasks) {
return tasks.reduce((promiseChain, currentTask) => {
return promiseChain.then(chainResults => currentTask().then(currentResult => [...chainResults, currentResult]))
}, Promise.resolve([]));
};
const CHROME_TOOLS = {
copy: copy // copy is a Command Line not accessible within a new Promise(...) or setTimeout(...)
};
const RESOLVE = {
more : null,
previous: null,
};
//--------------------------------------------------
// Main logic
//--------------------------------------------------
let tasks = [
// Disable image loading (to save bandwith and CPU)
() => (function() {
let node = document.createElement('style');
node.setAttribute('id', 'show-no-image-trick');
node.appendChild(document.createTextNode(`img { display: none !important; }`));
document.head.appendChild(node);
return Promise.resolve(true);
})(),
// Load more comments
() => (function showMore() {
if (!RESOLVE.more) {
return new Promise((resolve) => {
RESOLVE.more = resolve;
showMore();
});
}
let button = document.querySelector('.comments-comments-list__load-more-comments-button');
if (!button) {
console.log('*** Finished loading more comments')
return RESOLVE.more(true);
}
button.click && button.click();
// wait for new comments to load
setTimeout(showMore, wait || 1000);
})(),
// Load previous comments (within a thread)
() => (function showPrevious() {
if (!RESOLVE.previous) {
return new Promise((resolve) => {
RESOLVE.previous = resolve;
showPrevious();
});
}
let button = document.querySelector('.button.show-prev-replies');
if (!button) {
console.log('*** Finished loading previous comments')
return RESOLVE.previous(true);
}
button.click && button.click();
// wait for previous comments to load
setTimeout(showPrevious, wait || 1000);
})(),
// Retrieve LinkedIn profile URL from post & replies
() => new Promise(function(resolve) {
let comments = [...document.querySelectorAll(".comments-comment-item__post-meta"),
...document.querySelectorAll(".comments-reply-item__post-meta")];
let profiles = Array.from(new Set(comments.map(cmt => cmt.lastElementChild.href)));
let csv = profiles.join('\n');
// copy complete csv string to clipboard
CHROME_TOOLS.copy(csv);
// signal user that process is complete
let message = 'You can now paste ' + profiles.length + ' entries in Excel, Google Sheets, ...';
if (window.Notification && Notification.permission !== 'denied') {
Notification.requestPermission(function(status) { // status is "granted", if accepted by user
var n = new Notification('Job completed', {
body: message,
icon: LINKEDIN_ICON
});
});
} else {
alert(message);
}
return resolve(profiles.length);
})
];
promiseSerializer(tasks)
.then(values => { console.log(values); })
.finally(() => {
// show back images
let node = document.querySelector('style#show-no-image-trick');
if (!node) { return; }
node.remove();
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment