Notebooks >> Scripts
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

215 lines
8.0 KiB

import json
import re
import time
from selenium import webdriver
from selenium.common.exceptions import (
ElementClickInterceptedException,
NoSuchElementException,
)
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
class EasyApplyLinkedin:
def __init__(self, data):
"""Parameter initialization"""
self.email = data["email"]
self.password = data["password"]
self.keywords = data["keywords"]
self.location = data["location"]
self.driver = webdriver.Chrome(data["driver_path"])
def login_linkedin(self):
"""This function logs into your personal LinkedIn profile"""
# go to the LinkedIn login url
self.driver.get("https://www.linkedin.com/login")
# introduce email and password and hit enter
login_email = self.driver.find_element_by_name("session_key")
login_email.clear()
login_email.send_keys(self.email)
login_pass = self.driver.find_element_by_name("session_password")
login_pass.clear()
login_pass.send_keys(self.password)
login_pass.send_keys(Keys.RETURN)
def job_search(self):
"""This function goes to the 'Jobs' section a looks for all the jobs that matches the keywords and location"""
# go to Jobs
jobs_link = self.driver.find_element_by_link_text("Jobs")
jobs_link.click()
# search based on keywords and location and hit enter
search_keywords = self.driver.find_element_by_css_selector(
".jobs-search-box__text-input[aria-label='Search jobs']"
)
search_keywords.clear()
search_keywords.send_keys(self.keywords)
search_location = self.driver.find_element_by_css_selector(
".jobs-search-box__text-input[aria-label='Search location']"
)
search_location.clear()
search_location.send_keys(self.location)
search_location.send_keys(Keys.RETURN)
def filter(self):
"""This function filters all the job results by 'Easy Apply'"""
# select all filters, click on Easy Apply and apply the filter
all_filters_button = self.driver.find_element_by_xpath(
"//button[@data-control-name='all_filters']"
)
all_filters_button.click()
time.sleep(1)
easy_apply_button = self.driver.find_element_by_xpath(
"//label[@for='f_LF-f_AL']"
)
easy_apply_button.click()
time.sleep(1)
apply_filter_button = self.driver.find_element_by_xpath(
"//button[@data-control-name='all_filters_apply']"
)
apply_filter_button.click()
def find_offers(self):
"""This function finds all the offers through all the pages result of the search and filter"""
# find the total amount of results (if the results are above 24-more than one page-, we will scroll trhough all available pages)
total_results = self.driver.find_element_by_class_name(
"display-flex.t-12.t-black--light.t-normal"
)
total_results_int = int(total_results.text.split(" ", 1)[0].replace(",", ""))
print(total_results_int)
time.sleep(2)
# get results for the first page
current_page = self.driver.current_url
results = self.driver.find_elements_by_class_name(
"occludable-update.artdeco-list__item--offset-4.artdeco-list__item.p0.ember-view"
)
# for each job add, submits application if no questions asked
for result in results:
hover = ActionChains(self.driver).move_to_element(result)
hover.perform()
titles = result.find_elements_by_class_name(
"job-card-search__title.artdeco-entity-lockup__title.ember-view"
)
for title in titles:
self.submit_apply(title)
# if there is more than one page, find the pages and apply to the results of each page
if total_results_int > 24:
time.sleep(2)
# find the last page and construct url of each page based on the total amount of pages
find_pages = self.driver.find_elements_by_class_name(
"artdeco-pagination__indicator.artdeco-pagination__indicator--number"
)
total_pages = find_pages[len(find_pages) - 1].text
total_pages_int = int(re.sub(r"[^\d.]", "", total_pages))
get_last_page = self.driver.find_element_by_xpath(
"//button[@aria-label='Page " + str(total_pages_int) + "']"
)
get_last_page.send_keys(Keys.RETURN)
time.sleep(2)
last_page = self.driver.current_url
total_jobs = int(last_page.split("start=", 1)[1])
# go through all available pages and job offers and apply
for page_number in range(25, total_jobs + 25, 25):
self.driver.get(current_page + "&start=" + str(page_number))
time.sleep(2)
results_ext = self.driver.find_elements_by_class_name(
"occludable-update.artdeco-list__item--offset-4.artdeco-list__item.p0.ember-view"
)
for result_ext in results_ext:
hover_ext = ActionChains(self.driver).move_to_element(result_ext)
hover_ext.perform()
titles_ext = result_ext.find_elements_by_class_name(
"job-card-search__title.artdeco-entity-lockup__title.ember-view"
)
for title_ext in titles_ext:
self.submit_apply(title_ext)
else:
self.close_session()
def submit_apply(self, job_add):
"""This function submits the application for the job add found"""
print("You are applying to the position of: ", job_add.text)
job_add.click()
time.sleep(2)
# click on the easy apply button, skip if already applied to the position
try:
in_apply = self.driver.find_element_by_xpath(
"//button[@data-control-name='jobdetails_topcard_inapply']"
)
in_apply.click()
except NoSuchElementException:
print("You already applied to this job, go to next...")
pass
time.sleep(1)
# try to submit if submit application is available...
try:
submit = self.driver.find_element_by_xpath(
"//button[@data-control-name='submit_unify']"
)
submit.send_keys(Keys.RETURN)
# ... if not available, discard application and go to next
except NoSuchElementException:
print("Not direct application, going to next...")
try:
discard = self.driver.find_element_by_xpath(
"//button[@data-test-modal-close-btn]"
)
discard.send_keys(Keys.RETURN)
time.sleep(1)
discard_confirm = self.driver.find_element_by_xpath(
"//button[@data-test-dialog-primary-btn]"
)
discard_confirm.send_keys(Keys.RETURN)
time.sleep(1)
except NoSuchElementException:
pass
time.sleep(1)
def close_session(self):
"""This function closes the actual session"""
print("End of the session, see you later!")
self.driver.close()
def apply(self):
"""Apply to job offers"""
self.driver.maximize_window()
self.login_linkedin()
time.sleep(5)
self.job_search()
time.sleep(5)
self.filter()
time.sleep(2)
self.find_offers()
time.sleep(2)
self.close_session()
if __name__ == "__main__":
with open("config.json") as config_file:
data = json.load(config_file)
bot = EasyApplyLinkedin(data)
bot.apply()