This article was originally published on Medium and can be found here

What is LinkedIn?

It is a social media for professionals to showcase their achievements, for some to network and find jobs, and for others to use it as Facebook.

Why are we here?

Automation stems from the desire for efficiency. So, here is a short story.

Harry, my friend, posts on the WhatsApp group a google excel sheet in which all have to enter their LinkedIn profile URL so we can connect. Sounds great! It doesn’t matter if you know people, but “Gotta Catch ’Em All”.

I wake up in the morning and check the sheet and there are 246 entries. My actions looked as follows -

Click on Google Sheet tab > Click on Profile URL > Click “Connect” once the LinkedIn page loads > Close LinkedIn tab > Repeat.

Let’s automate it.

Scripting Requirements

Setting up environment

  1. Install Python from here
  2. Create a virtual environment “env” under the project directory “automate_linkedin”
    python -m venv \base_path\automate_linkedin\env
  3. Install Selenium and Pandas
    pip install selenium
    pip install pandas
  4. Download geckodriver from here and extract it under the project directory

Crack your knuckles to Code

  1. Get the data from csv file and generate a list of LinkedIn profile URL

    linkedin_database = pandas.read_csv("linkedin_database.csv")
    profile_url_list = list(linkedin_database.iloc[0:, 2])

    where our CSV is in the format

    csv structure
    csv structure
  2. Provide the path for geckodriver for the Firefox browser and start the session

    service = Service('geckodriver-v0.31.0-win64\\geckodriver.exe')
    browser = webdriver.Firefox(service=service)
  3. Automate Login

    • Load the base login URL of LinkedIn
      url = "https://www.linkedin.com/"
      browser.get(url)
    • Inspect web page and find ID for HTML element for username text field and password text field Inspect login page
    • Get element by ID discovered above using selenium find_element method
      username = browser.find_element(By.ID,"session_key")
      password = browser.find_element(By.ID,"session_password")
    • Next, we are sending keys, this is similar to entering keys using your keyboard. For this we use selenium send_keys method
      username.send_keys("<Enter your email id>")
      password.send_keys("<Enter your password>")
    • Finally, inspect web page and find class_name for HTML element for submit button, get that element using class_name and click it using click method
      browser.find_element(By.CLASS_NAME,"sign-in-form__submit-button").click()
  4. Sending Connection Requests

    • Fetch each profile URL, check if it is a valid URL and then load the URL and wait for a few seconds till the web page is completely loaded

      for profile_url in profile_url_list:
            print(profile_url)
            if not profile_url or pandas.isnull(profile_url):
                  print("Empty String\n")
                  continue
            try:
                  browser.get(profile_url)
            except InvalidArgumentException:
                  print("Bad profile URL\n")
                  continue
            sleep(10)
    • Understanding different scenarios we may encounter while sending a connection request

      • Scenario 1: “Connect” button is on screen itself
        Connect button is visible on screen
        “Connect” button is visible on screen
      • Scenario 2: “Connect” button is under “More” dropdown
        Connect action under More dropdown
        “Connect” action under “More” dropdown
      • Scenario 3: You are already connected with that user or you had previously sent a request which is in “Pending” mode

        Hence, we have to handle Scenarios 1 and 2 and ignore any instances of 3rd.

    • Finding the XPath to the “Connect button”. More on XPath can be found here.

      • Scenario 1: For this, we only need to find XPath to “Connect” button on the screen, get element by XPath and then click on it

        def check_exists_by_xpath(browser,xpath):
          try:
              browser.find_element(By.XPATH,xpath)
          except NoSuchElementException:
              return False
          return True
        
        xpath="//main[@id='main']/section[1]/div[2]/div[3]/div[1]/button[1]/span[contains(.,'Connect')]"
        connect_xpath="//main[@id='main']/section[1]/div[2]/div[3]/div[1]/button[1]"
        
        if check_exists_by_xpath(browser,xpath):
          browser.find_element(By.XPATH,connect_xpath).click()
          check_popup(browser)
          print("Connected\n")
      • Scenario 2: Here we first have to find XPath to “More” dropdown > get that element > click on it > find Xpath to “Connect” button under it > get that element > click on it

        more_xpath="//main[@id='main']/section[1]/div[2]/div[3]/div[1]//button[contains(@aria-label, 'More actions')]"
        more_connect_xpath="//main[@id='main']/section[1]/div[2]/div[3]/div[1]//button[contains(@aria-label, 'More actions')]/parent::node()/div/div/ul//div/span[text()='Connect']"
        if check_exists_by_xpath(browser, more_xpath):
          browser.find_element(By.XPATH,more_xpath).click()
          if check_exists_by_xpath(browser, more_connect_xpath):
              browser.find_element(By.XPATH,more_connect_xpath).click()
              check_popup(browser)
              print("Connected\n")
          else:
              print("No connection option under More button\n")
    • Handling the different pop-ups post clicking “Connect” Let’s discover the different pop-ups we get on clicking “Connect”

      • Pop-up 1:
        Customize Invitation pop-up
        “Customize Invitation” pop-up
        def check_exists(element,browser,sel):
          try:
              browser.find_element(element,sel)
          except NoSuchElementException:
              return False
          return True
          if check_exists(By.CSS_SELECTOR,browser,'[aria-label="Send now"]'):
              browser.find_element(By.CSS_SELECTOR,'[aria-label="Send now"]').click

        In the above code snippet, we are trying to find an identifier for “Send” button which here is CSS_SELECTOR ‘[aria-label=”Send now”]’ for that element and then clicking on it.

      • Pop-up 2:
        How do you know pop-up
        “How do you know” pop-up
        if check_exists(By.CSS_SELECTOR,browser,'[aria-label="Other"]'):
          browser.find_element(By.CSS_SELECTOR,'[aria-label="Other"]').click()
          browser.find_element(By.CSS_SELECTOR,'[aria-label="Connect"]').click()

        In the above code snippet, we are trying to find an identifier for “Other” button which here is CSS_SELECTOR ‘[aria-label=”Other”]’ and then for “Connect” which is CSS_SELECTOR ‘[aria-label=”Connect”]’. “Connect” will only get activated once “Other” or any one of the options is selected.

      • Pop-up 3:
        Prefers to be followed pop-up
        “Prefers to be followed” pop-up
        if check_exists(By.CSS_SELECTOR,browser,'[aria-label="Connect"]'):
          browser.find_element(By.CSS_SELECTOR,'[aria-label="Connect"]').click()

        In the above code snippet, we are trying to find an identifier for “Connect” which is CSS_SELECTOR ‘[aria-label=”Connect”]’ and then clicking on it.

        These pop-ups may come up one after the another and hence we create some kind of recursive method till all pop-ups are cleared.

        def check_popup(browser):
          if check_exists(By.CSS_SELECTOR,browser,'[aria-label="Send now"]'):
              browser.find_element(By.CSS_SELECTOR,'[aria-label="Send now"]').click()
          elif check_exists(By.CSS_SELECTOR,browser,'[aria-label="Other"]'):
              browser.find_element(By.CSS_SELECTOR,'[aria-label="Other"]').click()
              browser.find_element(By.CSS_SELECTOR,'[aria-label="Connect"]').click()
              check_popup(browser)
          elif check_exists(By.CSS_SELECTOR,browser,'[aria-label="Connect"]'):
              browser.find_element(By.CSS_SELECTOR,'[aria-label="Connect"]').click()
              check_popup(browser)
          return

Now sit back and enjoy!!!

Note: This article serves as an educational tool on the use of selenium and does not encourage breaking of any LinkedIn rules and policies and as such should not be used in any form that harms anyone.

Complete code is available on my Github repo 👇

https://github.com/BobErgot/LinkedIn-Connection-Request-Bot