A professional-grade Python framework built with Playwright to automate job market intelligence. This tool executes precision searches, applies deterministic filtering to results, and delivers a centralized daily intelligence report.
As a Senior QA-driven project, this tool goes beyond simple scraping:
- Native Event Simulation: Bypasses "lazy-loading" UI constraints by simulating native hardware mouse-wheel events at specific viewport coordinates.
- Deterministic Filtering: Implements Regex-based title validation to ensure high-relevance targeting for Lead and Senior roles.
- Session Injection: Securely manages LinkedIn authentication via state-sharing (
session.json), eliminating the need for repeated logins and reducing bot-detection risk.
| Search Keywords | Locations | Time Filter |
|---|---|---|
Software QA Lead |
New Jersey · Remote | Last 24 hours |
QA Automation Engineer |
New Jersey · Remote | Last 24 hours |
Results are deduplicated by LinkedIn job ID and exported to:
data/jobs/AutoJobSearch_Antigravity_YYYY-MM-DD.csvYou receive an email at 5 AM with:
- A dark-mode HTML summary table (job count, pay rate, remote stats)
- The full CSV attached (title, company, location, pay rate, job description, apply link)
- Python 3.11+
- Windows 10/11 (for Task Scheduler)
- A Gmail account with an App Password
cd AutoJobSearch_Antigravity
pip install -r requirements.txt
playwright install chromiumCopy the template and fill in your credentials:
copy .env.example .envOpen .env and edit:
EMAIL_SENDER=your_gmail@gmail.com
EMAIL_PASSWORD=xxxxxxxxxxx # 16-char Gmail App Password (no spaces needed)
EMAIL_RECIPIENT=your_gmail@gmail.com
LINKEDIN_EMAIL=your_linkedin@email.com
LINKEDIN_PASSWORD=your_linkedin_password
⚠️ 2-Step Verification must be ON before this option appears.
- Go to myaccount.google.com → Security
- Enable 2-Step Verification if not already on
- Search "App Passwords" in the search bar
- Select Mail + Windows Computer → Generate
- Copy the 16-character password → paste into
.envasEMAIL_PASSWORD
This saves your session so future runs are fully automated:
python main.py --loginA browser window opens → log in → press ENTER in the terminal.
Your session is saved to data/session.json and reused automatically.
Session expires? Just run
--loginagain.
python setup_scheduler.pyVerify in Windows Task Scheduler (taskschd.msc) that
AutoJobSearch_Antogravity_Scraper appears under Task Scheduler Library.
| Command | Description |
|---|---|
python main.py |
Full run: scrape → CSV → email |
python main.py --login |
Re-authenticate LinkedIn session |
python main.py --dry-run |
Scrape + CSV, preview email in terminal (no send) |
python main.py --no-email |
Scrape + CSV only, skip email |
python main.py --test-email |
Re-send the most recent CSV as email |
python setup_scheduler.py |
Register 5 AM daily task |
python setup_scheduler.py --status |
Check task details |
python setup_scheduler.py --remove |
Delete the scheduled task |
AutoJobSearch_Antigravity/
├── scraper/
│ ├── browser_config.py # Stealth Playwright setup + session management
│ ├── linkedin_scraper.py # Core scraper — runs all 4 searches
│ └── job_parser.py # CSS-selector data extraction helpers
├── notifier/
│ └── email_sender.py # Gmail SMTP + dark-mode HTML email
├── config/
│ └── settings.py # All config loaded from .env
├── data/
│ ├── session.json # LinkedIn session cookies (gitignored)
│ └── jobs/ # Output CSVs (gitignored)
├── logs/
│ └── scraper.log # Rotating log (gitignored)
├── main.py # Entry point
├── setup_scheduler.py # Windows Task Scheduler helper
├── requirements.txt
├── .env # Your credentials (gitignored)
└── .env.example # Template
| Column | Description |
|---|---|
title |
Job title |
company |
Hiring company |
location |
Listed location |
pay_rate |
Salary / hourly rate (if shown) |
job_description |
Full JD text |
apply_link |
Direct LinkedIn apply URL |
search_keyword |
Which keyword matched |
search_location |
New Jersey or Remote |
scraped_at |
Timestamp of extraction |
job_id |
LinkedIn internal job ID |
Your session expired. Run python main.py --login to refresh.
Make sure EMAIL_PASSWORD is a Gmail App Password, not your regular Gmail password.
Also confirm 2-Step Verification is enabled on the account.
- LinkedIn may be throttling requests — the script uses random delays to minimize this.
- Check
logs/scraper.logfor details. - Try running manually first:
python main.py --dry-run
- Check
taskschd.msc→ right-click the task → Run manually to test. - Ensure the task uses the correct Python path:
python setup_scheduler.py --status.
Scraping LinkedIn is against their Terms of Service. This tool is for personal, educational use only. Use responsibly and at your own risk.