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

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

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

Billboard image

Imagine monitoring that's actually built for developers

Join Vercel, CrowdStrike, and thousands of other teams that trust Checkly to streamline monitor creation and configuration with Monitoring as Code.

Start Monitoring

👋 Kindness is contagious

Immerse yourself in a wealth of knowledge with this piece, supported by the inclusive DEV Community—every developer, no matter where they are in their journey, is invited to contribute to our collective wisdom.

A simple “thank you” goes a long way—express your gratitude below in the comments!

Gathering insights enriches our journey on DEV and fortifies our community ties. Did you find this article valuable? Taking a moment to thank the author can have a significant impact.

Okay