Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save sanjayka1999/89a153c209be5e21dfa1650d516922d3 to your computer and use it in GitHub Desktop.

Select an option

Save sanjayka1999/89a153c209be5e21dfa1650d516922d3 to your computer and use it in GitHub Desktop.
LinkedIn Job Bot
/**
* LinkedIn Job Application Bot for Cloud Computing Roles
* Focus: Nashua, NH and 100-mile radius
* Targets: Entry-level cloud jobs and internships
*/
const LinkedInJobBot = {
config: {
// Timing controls (in milliseconds)
scrollDelay: 2000,
actionDelay: 3000,
nextPageDelay: 5000,
// Application limits
maxApplications: 30, // Safety limit
applicationsSent: 0,
// Job search parameters
jobTitles: [
"Cloud Engineer",
"AWS Engineer",
"Azure Administrator",
"Cloud Support",
"DevOps Engineer",
"Cloud Intern"
],
experienceLevel: "1", // 1=Entry level, 2=Associate, etc.
radius: "100", // miles
location: "Nashua, New Hampshire, United States",
// Personalization
addNote: true,
note: `I'm a recent Computer Science graduate with cloud certifications excited to apply for this {{jobTitle}} position. My skills in {{skills}} align well with your requirements.`,
// Skills to highlight (will be randomly selected for variation)
skills: [
"AWS services",
"Azure fundamentals",
"Terraform",
"Docker",
"Kubernetes",
"CI/CD pipelines",
"Cloud security"
]
},
// Initialize the bot
init: function() {
console.log("Starting LinkedIn Job Application Bot for Cloud Roles...");
this.navigateToJobsPage();
},
// Navigate to LinkedIn jobs search with our parameters
navigateToJobsPage: function() {
const titleParam = this.config.jobTitles.map(t => encodeURIComponent(t)).join("%20OR%20");
const url = `https://www.linkedin.com/jobs/search/?distance=${this.config.radius}&f_E=${this.config.experienceLevel}&geoId=102571732&keywords=${titleParam}&location=${encodeURIComponent(this.config.location)}`;
console.log(`Navigating to: ${url}`);
window.location.href = url;
// Start the process after page loads
setTimeout(() => this.preparePage(), 5000);
},
// Prepare the page by scrolling and loading all jobs
preparePage: function() {
console.log("Preparing page...");
this.scrollToBottom();
},
scrollToBottom: function() {
window.scrollTo(0, document.body.scrollHeight);
console.log("Scrolled to bottom, waiting for jobs to load...");
setTimeout(() => {
if (this.hasMoreJobs()) {
this.scrollToBottom();
} else {
this.processJobs();
}
}, this.config.scrollDelay);
},
// Check if more jobs are loading
hasMoreJobs: function() {
const loadingIndicator = document.querySelector('.jobs-search-two-pane__loading-indicator');
return loadingIndicator && loadingIndicator.style.display !== 'none';
},
// Main function to process and apply to jobs
processJobs: function() {
const jobListings = document.querySelectorAll('.jobs-search-results__list-item');
console.log(`Found ${jobListings.length} cloud-related jobs`);
if (jobListings.length === 0) {
console.log("No jobs found matching criteria");
return;
}
// Filter for Easy Apply jobs first
const easyApplyJobs = Array.from(jobListings).filter(job => {
return job.querySelector('.job-card-container__apply-method')?.textContent.includes('Easy Apply');
});
console.log(`Found ${easyApplyJobs.length} Easy Apply cloud jobs`);
if (easyApplyJobs.length > 0) {
this.applyToJobs(easyApplyJobs);
} else {
console.log("No Easy Apply jobs found. Consider manual applications.");
this.tryNextPage();
}
},
// Apply to a list of jobs
applyToJobs: function(jobs) {
if (this.config.applicationsSent >= this.config.maxApplications) {
console.log(`Reached maximum application limit of ${this.config.maxApplications}`);
return;
}
const job = jobs[0];
const jobTitle = job.querySelector('.job-card-list__title')?.textContent.trim() || 'cloud position';
const company = job.querySelector('.job-card-container__primary-description')?.textContent.trim() || '';
console.log(`Applying to: ${jobTitle} at ${company}`);
job.scrollIntoView();
job.click();
setTimeout(() => {
this.handleEasyApply(jobTitle);
// Remove this job from our list
jobs.shift();
// Continue with next job after delay
if (jobs.length > 0 && this.config.applicationsSent < this.config.maxApplications) {
setTimeout(() => this.applyToJobs(jobs), this.config.actionDelay * 2);
} else {
this.tryNextPage();
}
}, this.config.actionDelay);
},
// Handle the Easy Apply process
handleEasyApply: function(jobTitle) {
const easyApplyButton = document.querySelector('.jobs-apply-button');
if (!easyApplyButton) {
console.log("Easy Apply button not found");
return;
}
easyApplyButton.click();
setTimeout(() => {
this.completeApplicationForms(jobTitle);
}, this.config.actionDelay);
},
// Complete the application forms
completeApplicationForms: function(jobTitle) {
const forms = document.querySelectorAll('.jobs-easy-apply-form-section__grouping');
if (forms.length === 0) {
console.log("No application forms found");
this.closeApplication();
return;
}
console.log(`Completing ${forms.length} application sections...`);
// Randomly select 2-3 skills to mention
const shuffledSkills = [...this.config.skills].sort(() => 0.5 - Math.random());
const selectedSkills = shuffledSkills.slice(0, 2 + Math.floor(Math.random() * 2));
// Personalize the note
const personalizedNote = this.config.note
.replace('{{jobTitle}}', jobTitle)
.replace('{{skills}}', selectedSkills.join(', '));
// Find text areas and fill them
const textAreas = document.querySelectorAll('textarea');
textAreas.forEach(area => {
if (area.placeholder.includes('message') || area.placeholder.includes('note')) {
area.value = personalizedNote;
area.dispatchEvent(new Event('input', { bubbles: true }));
}
});
// Handle follow-up questions
const questions = document.querySelectorAll('.jobs-easy-apply-form-element');
questions.forEach(q => {
const questionText = q.textContent.toLowerCase();
// Sample question handling - would need to be expanded
if (questionText.includes('years of experience')) {
const options = q.querySelectorAll('input[type="radio"]');
if (options.length >= 1) options[0].click(); // Select lowest experience
}
else if (questionText.includes('sponsorship')) {
const noButton = [...q.querySelectorAll('button')].find(b =>
b.textContent.toLowerCase().includes('no') ||
b.textContent.toLowerCase().includes('not needed')
);
if (noButton) noButton.click();
}
});
// Submit the application
setTimeout(() => {
this.submitApplication();
}, this.config.actionDelay);
},
// Submit the application
submitApplication: function() {
const submitButton = [...document.querySelectorAll('button')].find(b =>
b.textContent.toLowerCase().includes('submit application')
);
if (submitButton) {
submitButton.click();
this.config.applicationsSent++;
console.log(`Application #${this.config.applicationsSent} submitted successfully`);
// Close any success modal
setTimeout(() => {
const doneButton = [...document.querySelectorAll('button')].find(b =>
b.textContent.toLowerCase().includes('done')
);
if (doneButton) doneButton.click();
}, 2000);
} else {
console.log("Submit button not found - application may not have been sent");
this.closeApplication();
}
},
// Close the application without submitting
closeApplication: function() {
const discardButton = [...document.querySelectorAll('button')].find(b =>
b.textContent.toLowerCase().includes('discard')
);
if (discardButton) discardButton.click();
},
// Try to navigate to next page of results
tryNextPage: function() {
if (this.config.applicationsSent >= this.config.maxApplications) {
console.log(`Reached maximum application limit of ${this.config.maxApplications}`);
return;
}
const nextButton = document.querySelector('button[aria-label="Next"]');
if (nextButton && !nextButton.disabled) {
console.log("Moving to next page of results...");
nextButton.click();
setTimeout(() => this.preparePage(), this.config.nextPageDelay);
} else {
console.log("No more pages of results found");
}
}
};
// Start the bot
LinkedInJobBot.init();
@MarwanShehata
Copy link

MarwanShehata commented May 17, 2025

Ah I forgot, I have done something similar for another job board, called Joblum, it seemed better to start with something simple like this because their website is ALMOST static pages.
https://gist.github.com/MarwanShehata/18fb82b8280edf3d2489878d004bf930

image

@sanjayka1999
Copy link
Author

sanjayka1999 commented May 19, 2025 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment