Skip to content

Commit 7fc84e5

Browse files
committed
Improvement: MVP Product & Added Readme.md
1 parent 857502b commit 7fc84e5

File tree

2 files changed

+80
-93
lines changed

2 files changed

+80
-93
lines changed

README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
## Easy Apply LinkedIn Bot 🤖
2+
3+
[//]: # (Horizontal rule)
4+
***
5+
Need? Job Search is boring!!!
6+
7+
Clicking and scrolling through hundreds of job descriptions, and then applying to each one individually is a tedious process.
8+
9+
Use our bot to automate MOST of the process of applying to jobs on LinkedIn.
10+
11+
***
12+
13+
# How it works?
14+
15+
Bot will,
16+
1. Open LinkedIn and login with your credentials.
17+
2. Searches for your job title and location.
18+
3. Applies filters to show only Easy Apply jobs.
19+
4. Opens each job description, takes consent to and applies to the job.
20+
5. Moves to next job and repeats the process.
21+
22+
23+
# Current Usage
24+
25+
Please note that this bot is still in development.
26+
27+
Currently, the bot applies for contractor positions, however, with slight modification to filter settings, one can adjust
28+
for interships, full-times. This is a work in progress..
29+
30+
31+
# Video with Instructions
32+
Will be uploaded soon..
33+
34+
35+
# How to use?
36+
37+
1. Clone the repository.
38+
2. Create a `credentials.properties` file in root directory and add your LinkedIn credentials as follows:
39+
`username=<email>`
40+
\n
41+
`password=<password>`
42+
3. Install Java and necessary files
43+
4. Run `Main.java`
44+
5. Enjoy the Magic!

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

Lines changed: 36 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -84,120 +84,40 @@ public static void main(String[] args) {
8484
getSearchResultsFor(jobTitle);
8585
String closeMessagesButtonXPath = "/html/body/div[5]/div[4]/aside/div[1]/header/div[3]/button[2]";
8686
clickButtonByXPath(closeMessagesButtonXPath);
87-
//setFilters();
87+
setFilters();
8888
boolean choice = false;
8989
do {
90-
// <div id="ember2602" class="jobs-search-results-list__pagination pv5 artdeco-pagination ember-view"><!---->
91-
// <ul class="artdeco-pagination__pages artdeco-pagination__pages--number">
92-
// <li data-test-pagination-page-btn="1" id="ember2603" class="artdeco-pagination__indicator artdeco-pagination__indicator--number active selected ember-view"> <button aria-current="true" aria-label="Page 1" type="button">
93-
// <span>1</span>
94-
// </button>
95-
96-
// </li>
97-
// <li data-test-pagination-page-btn="2" id="ember2604" class="artdeco-pagination__indicator artdeco-pagination__indicator--number ember-view"> <button aria-label="Page 2" type="button" data-ember-action="" data-ember-action-2605="2605">
98-
// <span>2</span>
99-
// </button>
100-
101-
// </li>
102-
// </ul>
103-
// <div class="artdeco-pagination__page-state">
104-
// Page 1 of 2
105-
// </div>
106-
107-
// <!----></div>
108-
109-
// <div id="ember2602" class="jobs-search-results-list__pagination pv5 jobs-search-results-list__pagination--hide-last-page artdeco-pagination ember-view"><!---->
110-
// <ul class="artdeco-pagination__pages artdeco-pagination__pages--number">
111-
// <li data-test-pagination-page-btn="1" id="ember2993" class="artdeco-pagination__indicator artdeco-pagination__indicator--number active selected ember-view"> <button aria-current="true" aria-label="Page 1" type="button">
112-
// <span>1</span>
113-
// </button>
114-
115-
// </li>
116-
// <li data-test-pagination-page-btn="2" id="ember2994" class="artdeco-pagination__indicator artdeco-pagination__indicator--number ember-view"> <button aria-label="Page 2" type="button" data-ember-action="" data-ember-action-2995="2995">
117-
// <span>2</span>
118-
// </button>
119-
120-
// </li>
121-
// <li data-test-pagination-page-btn="3" id="ember2996" class="artdeco-pagination__indicator artdeco-pagination__indicator--number ember-view"> <button aria-label="Page 3" type="button" data-ember-action="" data-ember-action-2997="2997">
122-
// <span>3</span>
123-
// </button>
124-
125-
// </li>
126-
// <li data-test-pagination-page-btn="4" id="ember2998" class="artdeco-pagination__indicator artdeco-pagination__indicator--number ember-view"> <button aria-label="Page 4" type="button" data-ember-action="" data-ember-action-2999="2999">
127-
// <span>4</span>
128-
// </button>
129-
130-
// </li>
131-
// <li data-test-pagination-page-btn="5" id="ember3000" class="artdeco-pagination__indicator artdeco-pagination__indicator--number ember-view"> <button aria-label="Page 5" type="button" data-ember-action="" data-ember-action-3001="3001">
132-
// <span>5</span>
133-
// </button>
134-
135-
// </li>
136-
// <li data-test-pagination-page-btn="6" id="ember3002" class="artdeco-pagination__indicator artdeco-pagination__indicator--number ember-view"> <button aria-label="Page 6" type="button" data-ember-action="" data-ember-action-3003="3003">
137-
// <span>6</span>
138-
// </button>
139-
140-
// </li>
141-
// <li data-test-pagination-page-btn="7" id="ember3004" class="artdeco-pagination__indicator artdeco-pagination__indicator--number ember-view"> <button aria-label="Page 7" type="button" data-ember-action="" data-ember-action-3005="3005">
142-
// <span>7</span>
143-
// </button>
144-
145-
// </li>
146-
// <li data-test-pagination-page-btn="8" id="ember3006" class="artdeco-pagination__indicator artdeco-pagination__indicator--number ember-view"> <button aria-label="Page 8" type="button" data-ember-action="" data-ember-action-3007="3007">
147-
// <span>8</span>
148-
// </button>
149-
150-
// </li>
151-
// <li id="ember3008" class="artdeco-pagination__indicator artdeco-pagination__indicator--number ember-view"><button aria-label="Page 9" type="button" data-ember-action="" data-ember-action-3009="3009">
152-
// <span>…</span>
153-
// </button>
154-
// </li>
155-
// <li data-test-pagination-page-btn="40" id="ember3010" class="artdeco-pagination__indicator artdeco-pagination__indicator--number ember-view"> <button aria-label="Page 40" type="button" data-ember-action="" data-ember-action-3011="3011">
156-
// <span>40</span>
157-
// </button>
158-
159-
// </li>
160-
// </ul>
161-
// <div class="artdeco-pagination__page-state">
162-
// Page 1 of 40
163-
// </div>
164-
165-
// <!----></div>
90+
//
16691
// Scroll thru the job Description
92+
93+
16794
List<WebElement> jobCards = driver
16895
.findElements(By.xpath("/html/body/div[5]/div[3]/div[4]/div/div/main/div/div[1]/div/ul/li"));
16996
int i = 1;
170-
97+
17198
for (WebElement card : jobCards) {
17299
// /html/body/div[5]/div[3]/div[4]/div/div/main/div/div[1]/div/ul/li[1]
173100
WebElement view = driver.findElement(
174101
By.xpath("/html/body/div[5]/div[3]/div[4]/div/div/main/div/div[1]/div/ul/li[" + i + "]"));
175102
scrollToWebElement(view);
176-
// randomSleep(SHORT_SLEEP);
177-
178-
///html/body/div[5]/div[3]/div[4]/div/div/main/div/div[1]/div/ul/li[1]/div/div[1]/div[1]/div[2]/div[1]/a
179-
///html/body/div[5]/div[3]/div[4]/div/div/main/div/div[1]/div/ul/li[3]/div/div[1]/div[1]/div[2]/div[1]/a
180-
// get the aria label in this element as job Title In Card,
103+
// get the aria label in this element as job Title In Card,
181104
// if it contains any of the MUST_HAVE, then click on the card
182105
WebElement aTag = view.findElement(By.cssSelector(".disabled.ember-view.job-card-container__link.job-card-list__title"));
183106

184107
// Extract the aria-label content
185108
String jobTitleInCard = aTag.getAttribute("aria-label");
109+
logger.info("jobTitleInCard: " + jobTitleInCard);
186110

187111
// Print the content
188112

189-
// String jobTitleInCard = view.findElement(By.xpath("/html/body/div[5]/div[3]/div[4]/div/div/main/div/div[1]/div/ul/li["+i + "]/div/div[1]/div[1]/div[2]/div[1]/a")).getAttribute("aria-label");
190113
i++;
191114

192-
if (jobTitleInCard == null) {
193-
continue;
194-
}
195115
// process job Title in Card by removing special characters with space and split the job Title into words
196116
jobTitleInCard = jobTitleInCard.replaceAll("[^a-zA-Z0-9]", " ").toLowerCase();
197117
String[] jobTitleInCardWords = jobTitleInCard.split(" ");
198-
118+
199119
// check if any of the MUST_HAVE words are in the job Title in Card
200-
120+
201121
// scan the jobTitle for must not have words
202122
if(hasWords(jobTitleInCardWords, MUST_NOT_HAVE) || !hasWords(jobTitleInCardWords, MUST_HAVE))
203123
{
@@ -206,15 +126,33 @@ public static void main(String[] args) {
206126
}
207127
logger.info("Processing job: " + jobTitleInCard);
208128
card.click();
209-
129+
210130
// Skipping already applied Jobs
211131
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";
212132
if (!elementExists(easyApplyBtnInJobDesc)) {
213133
continue;
214134
}
215-
135+
216136
chooseToApply(scanner);
217137
}
138+
// click on the next page
139+
// List<WebElement> resultPages = driver.findElements(By.xpath(
140+
// "/html/body/div[4]/div[3]/div[4]/div/div/main/div/div[1]/div/div[5]/ul/li"));
141+
142+
// logger.info("There are " + resultPages.size() + " pages of results");
143+
// int page = 1;
144+
// for (WebElement pageButton : resultPages) {
145+
// scrollToWebElement(pageButton);
146+
// randomSleep(SHORT_SLEEP);
147+
// pageButton.click();
148+
// logger.info("Page " + page + " of " + resultPages.size());
149+
// randomSleep(MEDIUM_SLEEP);
150+
// jobCards = driver
151+
// .findElements(By.xpath("/html/body/div[5]/div[3]/div[4]/div/div/main/div/div[1]/div/ul/li"));
152+
// logger.info("There are " + jobCards.size() + " jobs on this page");
153+
// page++;
154+
// }
155+
// randomSleep(MEDIUM_SLEEP);
218156
choice = offerUserChoices();
219157
} while (choice);
220158
// close the browser
@@ -240,25 +178,29 @@ private static boolean hasWords(String[] jobTitleInCardWords, List<String> WORDS
240178
private static Boolean offerUserChoices() {
241179
String jobLocation = "United States";
242180
String jobTitle = "java developer";
243-
System.out.println("Choose from Options \n 1. Search new job Title \n 2.Change Job Location 3. exit\n");
181+
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");
244182
// take input integer from user
245183
int choice = scanner.nextInt();
246184
switch (choice) {
247185
case 1:
248186
System.out.println("Enter new job title");
249187
jobTitle = scanner.nextLine();
188+
getSearchResultsFor(jobTitle);
250189
break;
251190
case 2:
252191
System.out.println("Enter new job location");
253192
jobLocation = scanner.nextLine();
254193
break;
194+
case 3:
195+
System.out.println("Assuming you clicked on next page");
196+
break;
197+
255198
default:
256199
// log exiting
257200
logger.info("Exiting the program");
258201
return false;
259202
}
260203
// call searchForResults
261-
getSearchResultsFor(jobTitle);
262204
return true;
263205
}
264206

@@ -276,6 +218,7 @@ private static void chooseToApply(Scanner scanner) {
276218
{
277219
System.out.println("Exiting the program");
278220
closeBrowser();
221+
System.exit(0);
279222
}
280223
if (input.equalsIgnoreCase("yes") || input.equalsIgnoreCase("y")) {
281224
// Click on apply button

0 commit comments

Comments
 (0)