Last active
December 1, 2020 09:40
-
-
Save guillaumegarcia13/1a41ad19a7035cbd7cb98f65b385b037 to your computer and use it in GitHub Desktop.
Retrieve all LinkedIn profiles of people leaving a comment
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
/*==================================================================================================================== | |
* 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