Created
November 29, 2023 16:36
-
-
Save mohdabdin/804dc17ac1e064c28b2860cf2c37dbb1 to your computer and use it in GitHub Desktop.
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
""" | |
This script is used to automate the process of sending LinkedIn connection requests and messages to a list of people. | |
It uses Selenium to automate the process of logging in and sending connection requests and messages. | |
Author: Mohammad Abdin (https://www.linkedin.com/in/mohammad-abdin-779260147/) | |
Keep in mind this can break if LinkedIn changes their HTML structure. | |
""" | |
import pandas as pd | |
from selenium import webdriver | |
from selenium.webdriver.common.by import By | |
from selenium.webdriver.common.action_chains import ActionChains | |
import random | |
import time | |
driver = webdriver.Chrome() | |
actions = ActionChains(driver) | |
driver.get("https://www.linkedin.com/login") | |
def login(un, pw): | |
time.sleep(1) | |
u = driver.find_element(By.XPATH, "/html/body/div/main/div[3]/div[1]/form/div[1]/input") | |
p = driver.find_element(By.XPATH, "/html/body/div/main/div[3]/div[1]/form/div[2]/input") | |
time.sleep(3) | |
u.send_keys(un) | |
p.send_keys(pw) | |
time.sleep(1) | |
driver.find_element(By.XPATH, "/html/body/div/main/div[3]/div[1]/form/div[3]/button").click() | |
time.sleep(10) | |
def outreach(messages_, link, n): | |
k = 0 | |
page = 1 | |
results = [] | |
while True: | |
if k >= n: | |
break | |
driver.get(link + '&page=' + str(page)) | |
page += 1 | |
if page > 100: | |
driver.quit() | |
break | |
time.sleep(5) | |
page_results = driver.find_elements(By.CSS_SELECTOR, 'li.reusable-search__result-container') | |
for result in page_results: | |
if k >= n: | |
break | |
driver.execute_script("return arguments[0].scrollIntoView();", result) | |
driver.execute_script("window.scrollBy(0, -150);") | |
try: | |
name = result.find_element(By.XPATH, './/div/div/div[2]/div[1]/div[1]/div/span[1]/span/a/span/span[1]').text | |
headline = result.find_element(By.XPATH, './/div/div/div[2]/div[1]/div[2]/div[1]').text | |
location = result.find_element(By.XPATH, './/div/div/div[2]/div[1]/div[2]/div[2]').text | |
profile = result.find_element(By.XPATH, './/div/div/div[2]/div[1]/div[1]/div/span[1]/span/a').get_attribute('href') | |
cta = result.find_element(By.XPATH, './/div/div/div[3]/div/button') | |
cta_text = cta.find_element(By.XPATH, './/span').text | |
if cta_text == 'Connect': | |
cta.click() # Connect button | |
time.sleep(1) | |
driver.find_element(By.XPATH, '/html/body/div[3]/div/div/div[3]/button[1]').click() # add note button | |
time.sleep(1) | |
msg_body = random.choice(messages_) | |
first_name = name.split(' ')[0] | |
intro = f'Hey {first_name}! ' | |
msg = intro + msg_body | |
result.find_element(By.XPATH, '/html/body/div[3]/div/div/div[2]/div/textarea').send_keys(msg) # add msg | |
time.sleep(1) | |
result.find_element(By.XPATH, '/html/body/div[3]/div/div/div[3]/button[2]').click() # send invitation | |
k += 1 | |
row = [link, name, profile, headline, location, msg_body] | |
results.append(row) | |
time.sleep(0.5) | |
except Exception as e: | |
try: | |
driver.find_element(By.XPATH, '/html/body/div[3]/div/div/button').click() | |
except: | |
pass | |
df = pd.DataFrame(results, columns=['Search Link', 'Name', 'Profile Link', 'Headline', 'Location', 'Message']) | |
return df | |
### __INIT__ ### | |
if __name__ == '__main__': | |
search_link = 'https://www.linkedin.com/search/results/people/?keywords=digital%20agency%20seo&origin=SWITCH_SEARCH_VERTICAL' | |
# "Hey {first_name}," is added automatically | |
MSG = """I'm working on a no-code AI platform to help marketers incorporate recent AI leaps for internal tools and workflows. | |
Given your background in SEO I think you'll find it useful and I'd love to get your feedback. Would you be open to a quick chat soon? :) | |
""" | |
messages = [MSG] # add more messages to experiment, they will be chosen randomly | |
username = 'your_linkedin_email' | |
password = 'your_linkedin_password' | |
n_users = 50 # number of users to reach out to | |
login(username, password) | |
results = outreach(messages, search_link, n_users) | |
# you can save the results to a csv file or do whatever you want with them |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Updated fork with some additional functionality: https://gist.github.com/baberparweez/2baf20d4addce1dc05570c3938554a8d
Added
dotenv
for moving username and password out of code in a.env
file like this:LINKEDIN_USERNAME=username@email.com
LINKEDIN_PASSWORD=password
Added
argparse
for allowed keyword argument update.For example:
python3 linkedin_outreach.py --keyword "Mixed Media Advertising Agency"