Esse post vai mostrar um script para automatizar envio de conexões no linkedin.
Requisitos:
- Pesquise por palavras chaves dos perfis que vc quer conectar. ["#reactnative", "#vue", "Tech Recruiter"]
- Selecione a aba "Pessoas", se necessário, adicione filtros como localização ou empresa em que trabalham
- Abra o console do navegador (F12) e cole o script em anexo
🦧 veja como salvar esse script no navegador no final do post
IMPORTANTE
Lembre de modificar a mensagem em config.note e mudar a flag "addNote", caso tenha atingido o limite de mensagens de conexão personalizada.
// ==UserScript== | |
// @name New script linkedin.com | |
// @namespace Violentmonkey Scripts | |
// @match https://www.linkedin.com/search/results/people/* | |
// @grant none | |
// @version 1.0 | |
// @author - (see for the orginal author: https://gist.github.com/thealphadollar/7c0ee76664cbd28aecc1bd235f0202fd) - Ryan | |
// @description 2/2/2024, 7:56:04 PM | |
// ==/UserScript== | |
Linkedin = { | |
config: { | |
scrollDelay: 3000, | |
actionDelay: 2000, | |
nextPageDelay: 2000, | |
// set to -1 for no limit | |
maxRequests: -1, | |
totalRequestsSent: 0, | |
// set to false to skip adding note in invites | |
addNote: false, | |
note: "Fala, {{name}}! Vi que vc trabalha/trabalhou com vue e tenho interesse em me conectar com pessoas da comunidade. Por favor, considere aceitar minha solicitação :D", | |
}, | |
init: function (data, config) { | |
console.info("INFO: script initialized on the page..."); | |
console.debug( | |
"DEBUG: scrolling to bottom in " + config.scrollDelay + " ms" | |
); | |
setTimeout(() => this.scrollBottom(data, config), config.actionDelay); | |
}, | |
scrollBottom: function (data, config) { | |
window.scrollTo({ top: document.body.scrollHeight, behavior: "smooth" }); | |
console.debug("DEBUG: scrolling to top in " + config.scrollDelay + " ms"); | |
setTimeout(() => this.scrollTop(data, config), config.scrollDelay); | |
}, | |
scrollTop: function (data, config) { | |
window.scrollTo({ top: 0, behavior: "smooth" }); | |
console.debug( | |
"DEBUG: inspecting elements in " + config.scrollDelay + " ms" | |
); | |
setTimeout(() => this.inspect(data, config), config.scrollDelay); | |
}, | |
inspect: function (data, config) { | |
var totalRows = this.totalRows(); | |
console.debug("DEBUG: total search results found on page are " + totalRows); | |
if (totalRows >= 0) { | |
this.compile(data, config); | |
} else { | |
console.warn("WARN: end of search results!"); | |
this.complete(config); | |
} | |
}, | |
compile: function (data, config) { | |
var elements = document.querySelectorAll("button"); | |
data.pageButtons = [...elements].filter(function (element) { | |
return element.textContent.trim() === "Connect"; | |
}); | |
if (!data.pageButtons || data.pageButtons.length === 0) { | |
console.warn("ERROR: no connect buttons found on page!"); | |
console.info("INFO: moving to next page..."); | |
setTimeout(() => { | |
this.nextPage(config); | |
}, config.nextPageDelay); | |
} else { | |
data.pageButtonTotal = data.pageButtons.length; | |
console.info("INFO: " + data.pageButtonTotal + " connect buttons found"); | |
data.pageButtonIndex = 0; | |
var names = document.getElementsByClassName("entity-result__title-text"); | |
names = [...names].filter(function (element) { | |
return element.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.textContent.includes( | |
"Connect\n" | |
); | |
}); | |
data.connectNames = [...names].map(function (element) { | |
return element.innerText.split(" ")[0]; | |
}); | |
console.debug( | |
"DEBUG: starting to send invites in " + config.actionDelay + " ms" | |
); | |
setTimeout(() => { | |
this.sendInvites(data, config); | |
}, config.actionDelay); | |
} | |
}, | |
sendInvites: function (data, config) { | |
console.debug("remaining requests " + config.maxRequests); | |
if (config.maxRequests == 0) { | |
console.info("INFO: max requests reached for the script run!"); | |
this.complete(config); | |
} else { | |
console.debug( | |
"DEBUG: sending invite to " + | |
(data.pageButtonIndex + 1) + | |
" out of " + | |
data.pageButtonTotal | |
); | |
var button = data.pageButtons[data.pageButtonIndex]; | |
button.click(); | |
if (config.addNote && config.note) { | |
console.debug( | |
"DEBUG: clicking Add a note in popup, if present, in " + | |
config.actionDelay + | |
" ms" | |
); | |
setTimeout(() => this.clickAddNote(data, config), config.actionDelay); | |
} else { | |
console.debug( | |
"DEBUG: clicking done in popup, if present, in " + | |
config.actionDelay + | |
" ms" | |
); | |
setTimeout(() => this.clickDone(data, config), config.actionDelay); | |
} | |
} | |
}, | |
clickAddNote: function (data, config) { | |
var buttons = document.querySelectorAll("button"); | |
var addNoteButton = Array.prototype.filter.call(buttons, function (el) { | |
return el.textContent.trim() === "Add a note"; | |
}); | |
// adding note if required | |
if (addNoteButton && addNoteButton[0]) { | |
console.debug("DEBUG: clicking add a note button to paste note"); | |
addNoteButton[0].click(); | |
console.debug("DEBUG: pasting note in " + config.actionDelay); | |
setTimeout(() => this.pasteNote(data, config), config.actionDelay); | |
} else { | |
console.debug( | |
"DEBUG: add note button not found, clicking send on the popup in " + | |
config.actionDelay | |
); | |
setTimeout(() => this.clickDone(data, config), config.actionDelay); | |
} | |
}, | |
pasteNote: function (data, config) { | |
noteTextBox = document.getElementById("custom-message"); | |
noteTextBox.value = config.note.replace( | |
"{{name}}", | |
data.connectNames[data.pageButtonIndex] | |
); | |
noteTextBox.dispatchEvent( | |
new Event("input", { | |
bubbles: true, | |
}) | |
); | |
console.debug( | |
"DEBUG: clicking send in popup, if present, in " + | |
config.actionDelay + | |
" ms" | |
); | |
setTimeout(() => this.clickDone(data, config), config.actionDelay); | |
}, | |
clickDone: function (data, config) { | |
var buttons = document.querySelectorAll("button"); | |
var doneButton = Array.prototype.filter.call(buttons, function (el) { | |
// contains "Send" or "Done" in the button text | |
return ( | |
el.textContent.trim().includes("Send") || | |
el.textContent.trim().includes("Done") | |
); | |
}); | |
// Click the first send button | |
if (doneButton && doneButton[0]) { | |
console.debug("DEBUG: clicking send button to close popup"); | |
doneButton[0].click(); | |
} else { | |
console.log( | |
"DEBUG: send button not found, clicking close on the popup in " + | |
config.actionDelay | |
); | |
} | |
setTimeout(() => this.clickClose(data, config), config.actionDelay); | |
}, | |
clickClose: function (data, config) { | |
var closeButton = document.getElementsByClassName( | |
"artdeco-modal__dismiss artdeco-button artdeco-button--circle artdeco-button--muted artdeco-button--2 artdeco-button--tertiary ember-view" | |
); | |
if (closeButton && closeButton[0]) { | |
closeButton[0].click(); | |
} | |
console.info( | |
"INFO: invite sent to " + | |
(data.pageButtonIndex + 1) + | |
" out of " + | |
data.pageButtonTotal | |
); | |
config.maxRequests--; | |
config.totalRequestsSent++; | |
if (data.pageButtonIndex === data.pageButtonTotal - 1) { | |
console.debug( | |
"DEBUG: all connections for the page done, going to next page in " + | |
config.actionDelay + | |
" ms" | |
); | |
setTimeout(() => this.nextPage(config), config.actionDelay); | |
} else { | |
data.pageButtonIndex++; | |
console.debug( | |
"DEBUG: sending next invite in " + config.actionDelay + " ms" | |
); | |
setTimeout(() => this.sendInvites(data, config), config.actionDelay); | |
} | |
}, | |
nextPage: function (config) { | |
var pagerButton = document.getElementsByClassName( | |
"artdeco-pagination__button--next" | |
); | |
if ( | |
!pagerButton || | |
pagerButton.length === 0 || | |
pagerButton[0].hasAttribute("disabled") | |
) { | |
console.info("INFO: no next page button found!"); | |
return this.complete(config); | |
} | |
console.info("INFO: Going to next page..."); | |
pagerButton[0].click(); | |
setTimeout(() => this.init({}, config), config.nextPageDelay); | |
}, | |
complete: function (config) { | |
console.info( | |
"INFO: script completed after sending " + | |
config.totalRequestsSent + | |
" connection requests" | |
); | |
}, | |
totalRows: function () { | |
var search_results = document.getElementsByClassName("search-result"); | |
if (search_results && search_results.length != 0) { | |
return search_results.length; | |
} else { | |
return 0; | |
} | |
}, | |
}; | |
Linkedin.init({}, Linkedin.config); |
✨ Bônus ✨
🧑💻 Obrigado por chegar até aqui, se esse script te ajudou de alguma forma, considere curtir/compartilhar essa postagem
Para salvar esse script no navegador e sempre que quiser, eu recomendo usar a extensão 🦍 ViolentMonkey
Top comments (3)
Cara que post fenomenal, foi você que desenvolveu o script? gostaria de saber mais sobre esse ViolentMonkey? Será que não vale um post? Muito obrigado por compartilhar seu conhecimento 🦤.
Fala @raulferreirasilva, obrigado pelo seu comentário!
O ViolentMonkey é minha escolha em detrimento do TamperMonkey, que tem uma fama bem estranha sobre a política de privacidade e como os dados de usuário são processados nos servidores deles.
Vi vários comentários desse tipo aqui: https://www.reddit.com/r/FirefoxAddons/comments/128w9zf/comment/jelsfi1/?utm_source=share&utm_medium=web2x&context=3
Lembrando que existem outras alternativas para o ScriptRunner :D
Obrigado pelo interesse! 🦧
Cara valeu por avisar e compartilhar o link, vou dar uma analisada, gostei bastante do conteúdo, espero que traga mais. Obrigado por compartilhar seu conhecimento 🦤.