DEV Community

Cover image for Como se conectar com QUALQUER comunidade tech no linkedin
Ryan Lucas
Ryan Lucas

Posted on

3

Como se conectar com QUALQUER comunidade tech no linkedin

Esse post vai mostrar um script para automatizar envio de conexões no linkedin.

Requisitos:

  1. Pesquise por palavras chaves dos perfis que vc quer conectar. ["#reactnative", "#vue", "Tech Recruiter"]
  2. Selecione a aba "Pessoas", se necessário, adicione filtros como localização ou empresa em que trabalham
  3. 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

boy searching for connections on linkedin

Conecte-se comigo 👍

Linkedinho
X - App do passarinho

Top comments (3)

Collapse
 
raulferreirasilva profile image
Raul Ferreira

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 🦤.

Collapse
 
ryangst profile image
Ryan Lucas

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! 🦧

Collapse
 
raulferreirasilva profile image
Raul Ferreira • Edited

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 🦤.

SurveyJS custom survey software

JavaScript Form Builder UI Component

Generate dynamic JSON-driven forms directly in your JavaScript app (Angular, React, Vue.js, jQuery) with a fully customizable drag-and-drop form builder. Easily integrate with any backend system and retain full ownership over your data, with no user or form submission limits.

Learn more