Skip to content

Commit 6169cfc

Browse files
committed
Feature: Skips already applied jobs.
1 parent 5f2fc9e commit 6169cfc

File tree

1 file changed

+63
-80
lines changed

1 file changed

+63
-80
lines changed

src/main/java/org/example/Main.java

Lines changed: 63 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public static void main(String[] args) {
7676
loginToLinkedIn();
7777
randomSleep(SHORT_SLEEP);
7878

79-
String jobTitle = "full stack java developer";
79+
String jobTitle = "java developer";
8080
logger.info("Search by default for" + jobTitle);
8181
String jobLocation = "United States";
8282
getSearchResultsFor(jobTitle);
@@ -85,61 +85,64 @@ public static void main(String[] args) {
8585
setFilters();
8686
boolean choice = false;
8787
do {
88-
// Scroll thru the job Description
88+
8989
List<WebElement> jobCards = driver
90-
.findElements(By.xpath("/html/body/div[5]/div[3]/div[4]/div/div/main/div/div[1]/div/ul/li"));
90+
.findElements(By.xpath("/html/body/div[5]/div[3]/div[4]/div/div/main/div/div[1]/div/ul/li"));
9191
int i = 1;
9292

9393
for (WebElement card : jobCards) {
94-
// /html/body/div[5]/div[3]/div[4]/div/div/main/div/div[1]/div/ul/li[1]
9594
WebElement view = driver.findElement(
96-
By.xpath("/html/body/div[5]/div[3]/div[4]/div/div/main/div/div[1]/div/ul/li[" + i + "]"));
97-
98-
scrollToWebElement(view);
99-
// get the aria label in this element as job Title In Card,
100-
// if it contains any of the MUST_HAVE, then click on the card
101-
//
102-
WebElement aTag = view.findElement(By.cssSelector(".disabled.ember-view.job-card-container__link.job-card-list__title"));
103-
104-
// Extract the aria-label content
105-
String jobTitleInCard = aTag.getAttribute("aria-label");
106-
logger.info("jobTitleInCard: " + jobTitleInCard);
107-
108-
// Print the content
95+
By.xpath("/html/body/div[5]/div[3]/div[4]/div/div/main/div/div[1]/div/ul/li[" + i + "]"));
10996

110-
logger.info("Clicking job card with xpath: " + "/html/body/div[5]/div[3]/div[4]/div/div/main/div/div[1]/div/ul/li[" + i + "]");
111-
i++;
97+
scrollToWebElement(view);
11298

113-
// process job Title in Card by removing special characters with space and split the job Title into words
114-
jobTitleInCard = jobTitleInCard.trim().replaceAll("[^a-zA-Z0-9]", " ").toLowerCase();
115-
String[] jobTitleInCardWords = jobTitleInCard.split(" ");
99+
WebElement aTag = view.findElement(By.cssSelector(".disabled.ember-view.job-card-container__link.job-card-list__title"));
116100

117-
// check if any of the MUST_HAVE words are in the job Title in Card
101+
// Extract the aria-label content
102+
String jobTitleInCard = aTag.getAttribute("aria-label");
103+
logger.info("jobTitleInCard: " + jobTitleInCard);
104+
i++;
105+
// process job Title in Card by removing special characters except space with space and split the job Title into words
118106

119-
// scan the jobTitle for must not have words
120-
if(hasWords(jobTitleInCardWords, MUST_NOT_HAVE) || !hasWords(jobTitleInCardWords, MUST_HAVE))
121-
{
122-
logger.info("Skipping job: " + jobTitleInCard);
123-
continue;
124-
}
125-
logger.info("Processing job: " + jobTitleInCard);
126-
card.click();
107+
jobTitleInCard = jobTitleInCard.trim().replaceAll("[^a-zA-Z0-9]", " ");
108+
String[] jobTitleInCardWords = jobTitleInCard.split(" ");
109+
// for each word in job title, trim it and convert it to lower case using stream API
110+
jobTitleInCardWords = Arrays.stream(jobTitleInCardWords).map(String::trim).map(String::toLowerCase).toArray(String[]::new);
127111

128-
// Skipping already applied Jobs
129-
String easyApplyBtnInJobDesc = "/html/body/div[5]/div[3]/div[4]/div/div/main/div/div[2]/div/div[2]/div[1]/div/div[1]/div/div[1]/div[1]/div[4]/div/div/div/button";
130-
if (!elementExists(easyApplyBtnInJobDesc)) {
131-
continue;
132-
}
112+
// check if any of the MUST_HAVE words are in the job Title in Card
133113

134-
chooseToApply(scanner);
114+
// scan the jobTitle for must not have words
115+
if (hasWords(jobTitleInCardWords, MUST_NOT_HAVE) || !hasWords(jobTitleInCardWords, MUST_HAVE)) {
116+
logger.info("Skipping job: " + jobTitleInCard);
117+
continue;
135118
}
119+
logger.info("Processing job: " + jobTitleInCard);
120+
card.click();
136121

137-
choice = offerUserChoices();
138-
} while (choice);
139-
// close the browser
122+
randomSleep(SHORT_SLEEP);
123+
if (!isThisJobApplied()) {
124+
logger.info("Job was previously applied");
125+
continue;
126+
}
127+
logger.info("Job was not previously applied");
128+
chooseToApply(scanner);
129+
}
130+
choice = offerUserChoices();
131+
} while (choice);
140132
closeBrowser();
141133
}
142134

135+
private static boolean isThisJobApplied() {
136+
boolean containsClass;
137+
String easyApplyBtnDivXPath = "/html/body/div[5]/div[3]/div[4]/div/div/main/div/div[2]/div/div[2]/div[1]/div/div[1]/div/div[1]/div[1]/div[4]/div/div/div";
138+
139+
WebElement easyApplyBtnDiv = driver.findElement(By.xpath(easyApplyBtnDivXPath));
140+
// Check if the easyApplyBtnDiv has class "jobs-apply-button--top-card"
141+
String className = "jobs-apply-button--top-card";
142+
containsClass = (boolean) js.executeScript("return arguments[0].classList.contains(arguments[1])", easyApplyBtnDiv, className);
143+
return containsClass;
144+
}
145+
143146
private static void closeBrowser() {
144147
scanner.close();
145148
driver.quit();
@@ -155,16 +158,15 @@ private static boolean hasWords(String[] jobTitleInCardWords, List<String> WORDS
155158
}
156159
return mustHave;
157160
}
158-
161+
159162
private static boolean offerUserChoices() {
160163
String jobLocation = "United States";
161164
String jobTitle = "java developer";
162165
System.out.println("Choose from Options \n 1. Search new job Title \n 2. Change Job Location \n 3. Click next page & press 3 \n 4. exit \n");
163-
// take input integer from user
164166
int choice = scanner.nextInt();
165167
switch (choice) {
166168
case 1:
167-
Scanner sc2= new Scanner(System.in); //System.in is a standard input stream
169+
Scanner sc2 = new Scanner(System.in); //System.in is a standard input stream
168170
System.out.println("Enter new job title\n");
169171
jobTitle = sc2.nextLine(); //reads string
170172
getSearchResultsFor(jobTitle, true);
@@ -177,7 +179,7 @@ private static boolean offerUserChoices() {
177179
System.out.println("Assuming you clicked on next page");
178180
break;
179181

180-
default:
182+
default:
181183
// log exiting
182184
logger.info("Exiting the program");
183185
return false;
@@ -194,10 +196,9 @@ private static boolean elementExists(String xpath) {
194196
}
195197

196198
private static void chooseToApply(Scanner scanner) {
197-
System.out.println("Do you want to apply for the job? (y/n) e to exit\n");
199+
System.out.println("Do you want to apply for the job? (y/n) e to exit");
198200
String input = scanner.nextLine();
199-
if(input.trim().equalsIgnoreCase("e"))
200-
{
201+
if (input.trim().equalsIgnoreCase("e")) {
201202
System.out.println("Exiting the program");
202203
closeBrowser();
203204
System.exit(0);
@@ -207,7 +208,6 @@ private static void chooseToApply(Scanner scanner) {
207208
applyForThisJob();
208209
}
209210
}
210-
//disabled ember-view job-card-container__link job-card-list__title
211211

212212
private static void applyForThisJob() {
213213
WebElement applyButton = driver.findElement(By.xpath(
@@ -216,6 +216,13 @@ private static void applyForThisJob() {
216216

217217
// xpath for next button:
218218
// /html/body/div[3]/div/div/div[2]/div/div[2]/form/footer/div[2]/button
219+
220+
// submit button xpath:
221+
// /html/body/div[3]/div/div/div[2]/div/div[2]/div/footer/div[3]/button[2]
222+
/// html/body/div[3]/div/div/div[2]/div/div[2]/div/footer/div[2]/button[2]
223+
///html/body/div[3]/div/div/div[2]/div/div[2]/div/footer/div[3]/button[2]
224+
// scroll to the submit button
225+
219226
try {
220227
WebElement formFooter = driver.findElement(By.xpath(
221228
"/html/body/div[3]/div/div/div[2]/div/div[2]/form/footer"));
@@ -224,55 +231,33 @@ private static void applyForThisJob() {
224231
while (formFooter != null && nextButton != null) {
225232
scrollToWebElement(nextButton, false);
226233
logger.info("Found next button");
227-
//get next button aria lable
228-
String nextButtonAriaLabel = nextButton.getAttribute("aria-label");
229-
// log next button aria label
230-
logger.info("Next button aria label: " + nextButtonAriaLabel);
231234
nextButton.click();
232-
//Log Clicked next button
233235
logger.info("Clicked next button");
234236
randomSleep(SHORT_SLEEP);
235237
nextButton = formFooter.findElement(By.cssSelector(".artdeco-button--primary.ember-view"));
236238
}
237239

238-
// submit button xpath:
239-
// /html/body/div[3]/div/div/div[2]/div/div[2]/div/footer/div[3]/button[2]
240-
/// html/body/div[3]/div/div/div[2]/div/div[2]/div/footer/div[2]/button[2]
241-
// /html/body/div[3]/div/div/div[2]/div/div[2]/div/footer/div[3]/button[2]
242-
// scroll to the submit button
243-
244-
245-
}
246-
catch (Exception e) {
240+
} catch (Exception e) {
247241
logger.info(e.getMessage());
248242
}
249243
try {
250244
WebElement submitButton = driver.findElement(By.xpath(
251245
"/html/body/div[3]/div/div/div[2]/div/div[2]/div/footer")).findElement(By.cssSelector(".artdeco-button--primary.ember-view"));
252246
scrollToWebElement(submitButton, false);
253247
submitButton.click();
254-
randomSleep(LONG_SLEEP);
248+
randomSleep(MEDIUM_SLEEP);
255249
} catch (NoSuchElementException e) {
256250
WebElement submitButton = driver.findElement(By.xpath(
257-
"/html/body/div[3]/div/div/div[2]/div/div/form/footer/")).findElement(By.cssSelector(".artdeco-button--primary.ember-view"));
251+
"/html/body/div[3]/div/div/div[2]/div/div/form/footer")).findElement(By.cssSelector(".artdeco-button--primary.ember-view"));
258252
scrollToWebElement(submitButton, false);
259253
submitButton.click();
260-
randomSleep(LONG_SLEEP);
261-
}
262-
catch (Exception e) {
254+
randomSleep(MEDIUM_SLEEP);
255+
} catch (Exception e) {
263256
logger.info(e.getMessage());
264257
}
265258

266259
WebElement closeButton = driver.findElement(By.xpath("/html/body/div[3]/div/div/button"));
267260
closeButton.click();
268-
// Sleep for 5 secondsn
269-
270-
// single click submit jobs
271-
// <button aria-label="Submit application" id="ember1409" class="artdeco-button artdeco-button--2 artdeco-button--primary ember-view" type="button"><!---->
272-
//<span class="artdeco-button__text">
273-
// Submit application
274-
// </span></button>
275-
// xpath: /html/body/div[3]/div/div/div[2]/div/div/form/footer/div[3]/button
276261

277262
}
278263

@@ -328,25 +313,24 @@ private static void scrollToWebElement(WebElement contractExperienceLevel, boole
328313
if (sleep)
329314
randomSleep(SHORT_SLEEP);
330315
}
316+
331317
private static void clickWebElement(WebElement webElement) {
332318
js.executeScript("arguments[0].click();", webElement);
333319
randomSleep(SHORT_SLEEP);
334320
}
335321

336322
private static void getSearchResultsFor(String jobTitle) {
337-
///html/body/div[4]/header/div/div/div/div[2]/div[2]/div/div[2]/input[1]
323+
///html/body/div[4]/header/div/div/div/div[2]/div[2]/div/div[2]/input[1]
338324
WebElement searchField = driver.findElement(By.xpath("/html/body/div[5]/header/div/div/div/div[2]/div[2]/div/div/input[1]"));
339325
js.executeScript("arguments[0].scrollIntoView();", searchField);
340-
// scrollToWebElement(searchField);
341326
sendKeysToWebElement(jobTitle, searchField);
342327
sendKeysToWebElement("\n", searchField);
343328
}
344329

345-
private static void getSearchResultsFor(String jobTitle, boolean newSearch){
330+
private static void getSearchResultsFor(String jobTitle, boolean newSearch) {
346331

347332
WebElement searchField = driver.findElement(By.xpath("/html/body/div[5]/header/div/div/div/div[2]/div[1]/div/div/input[1]"));
348333
scrollToWebElement(searchField);
349-
// Clear the search field
350334
searchField.clear();
351335
sendKeysToWebElement(jobTitle, searchField);
352336
sendKeysToWebElement("\n", searchField);
@@ -360,7 +344,6 @@ private static void sendKeysToWebElement(String jobTitle, WebElement searchField
360344
private static void loginToLinkedIn() {
361345

362346
driver.get(linkedInSite);
363-
// Wait for page to load for 5 seconds
364347
enterIntoTextFieldById(emailInputBoxID, loginEmail);
365348
enterIntoTextFieldById(passwordInputBoxID, loginPass);
366349
String loginButtonXPath = "//button[@data-id='sign-in-form__submit-btn']";

0 commit comments

Comments
 (0)