
Job Scraper
- 5 installs
- 29.7k repo stars
- Updated August 4, 2026
- madslorentzen/ai-job-search
Scrapes Danish job sites via web search for new positions matching a profile, deduplicating against past runs and an application tracker.
About
Runs targeted web searches across Danish job sites, fetches and parses postings, deduplicates against seen jobs and a tracker CSV, and presents new matches with a quick fit rating. A developer uses it to find fresh job openings without repeats.
- Deduplicates against seen_jobs.json and job_search_tracker.csv
- Presents new jobs in a fit-sorted table; never fabricates postings
Job Scraper by the numbers
- 5 all-time installs (skills.sh)
- Ranked #1,723 of 2,715 Automation & Workflows skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/madslorentzen/ai-job-search --skill job-scraperAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 5 |
|---|---|
| repo stars | ★ 29.7k |
| Last updated | August 4, 2026 |
| Repository | madslorentzen/ai-job-search ↗ |
What it does
Scrapes Danish job sites via web search for new positions matching a profile, deduplicating against past runs and an application tracker.
Files
Job Scraper
---
How It Works
This skill searches multiple Danish job sites using targeted queries based on your profile, deduplicates against previously seen jobs and the application tracker, and presents new matches with a quick fit assessment.
Invocation
The user triggers this skill by saying things like:
- "Find new jobs"
- "Scrape for jobs"
- "Any new positions?"
- "/scrape"
Optional arguments:
- A focus area, e.g. "/scrape data science" or "/scrape geophysics"
- "broad" to run all search categories, e.g. "/scrape broad"
---
Execution Steps
Step 0: Load State
1. Read job_scraper/seen_jobs.json (create if missing - start with {"seen": {}}) 2. Read job_search_tracker.csv to extract already-applied companies+roles 3. Read search-queries.md (this directory) for the search strategy
Step 1: Search
Run WebSearch queries from search-queries.md. By default, run the top 3 priority categories. If the user said "broad", run all categories.
If the user specified a focus area (e.g. "data science"), prioritize queries from that category.
For each search:
- Use
WebSearchwith site-specific queries (jobindex.dk, linkedin.com/jobs, karriere.dk, etc.) - Target your configured geographic area
- Look for postings from the last 14 days
Step 2: Fetch & Parse
For each promising result from Step 1:
- Use
WebFetchto retrieve the job posting page - Extract: job title, company, location, posting date (or "recent"), URL, key requirements (brief), application deadline (if listed)
- Skip if the URL or company+title combo already exists in
seen_jobs.json - Skip if the company+role already appears in
job_search_tracker.csv
Step 3: Quick Fit Assessment
For each new job, do a rapid fit check (NOT the full evaluation from 04-job-evaluation.md - just a quick signal):
- High match: Role directly involves your core skills
- Medium match: Role is adjacent to your experience
- Low match: Role requires significant skills you lack
Step 4: Deduplicate & Store
1. Add ALL fetched jobs (new and skipped) to seen_jobs.json with structure:
{
"seen": {
"<url_or_company_title_key>": {
"title": "...",
"company": "...",
"url": "...",
"first_seen": "YYYY-MM-DD",
"fit": "high/medium/low",
"status": "new/skipped/evaluated"
}
}
}2. Only present jobs NOT already in the seen list or tracker.
Step 5: Present Results
Present new jobs in a table sorted by fit (high first):
## New Job Matches - YYYY-MM-DD
Found X new positions (Y high, Z medium, W low match).
| # | Fit | Title | Company | Location | Deadline | URL |
|---|-----|-------|---------|----------|----------|-----|
| 1 | High | ... | ... | ... | ... | [Link](...) |
### High-Match Highlights
For each high-match job, add 2-3 bullet points:
- Why it matches your profile
- Key requirements to check
- Any red flagsAfter presenting, ask:
"Want me to evaluate any of these in detail? Just give me the number(s)."
If the user picks a number, invoke the job-application-assistant skill workflow (fit evaluation first, then CV + cover letter if approved).
Step 6: Update Tracker (Optional)
If the user decides to apply to any job, add a row to job_search_tracker.csv.
---
Important Rules
1. Never fabricate job postings. Only present jobs found via actual WebSearch/WebFetch results. 2. Respect deduplication. Always check seen_jobs.json AND job_search_tracker.csv before presenting. 3. Focus on configured geographic area. Skip jobs that require relocation or are clearly outside commute range. 4. Only open positions. Skip postings with expired deadlines or those marked as closed. 5. Be efficient with WebFetch. Don't fetch every search result - use titles and snippets to pre-filter before fetching. 6. Parallel searches. Use the Agent tool or parallel WebSearch calls to speed up the search phase.
Search Queries for Job Scraper
<!-- SETUP: Customize these queries based on your skills, target roles, and location -->
Search Sites
Primary (Danish job market):
- jobindex.dk - largest Danish job board
- linkedin.com/jobs - LinkedIn job listings (filter: Denmark / your city)
- karriere.dk - IDA's job board (engineering/science roles)
- jobfinder.dk - another major Danish job board
- akademikernes.dk - academic union job board
Secondary (company career pages via Google):
- Direct Google searches with
site:filters for known target companies
Query Categories
Queries are grouped by priority. Each query should be combined with your location terms (e.g. "Copenhagen", "Sjælland", "Hovedstaden") where the site supports it.
Priority 1: [YOUR_PRIMARY_ROLE_TYPE]
These match your strongest and most desired career direction.
site:jobindex.dk "[YOUR_PRIMARY_JOB_TITLE]" [YOUR_CITY]
site:jobindex.dk "[YOUR_KEY_SKILL]" [YOUR_CITY]
site:linkedin.com/jobs "[YOUR_PRIMARY_JOB_TITLE]" [YOUR_COUNTRY]Priority 2: [YOUR_DOMAIN_EXPERTISE]
These match your domain expertise.
site:jobindex.dk [YOUR_DOMAIN_KEYWORD_1] [YOUR_CITY] OR [YOUR_REGION]
site:jobindex.dk [YOUR_DOMAIN_KEYWORD_2] [YOUR_COUNTRY]
site:linkedin.com/jobs [YOUR_DOMAIN_KEYWORD_1] [YOUR_CITY] [YOUR_COUNTRY]Priority 3: [YOUR_ADJACENT_ROLE_TYPE]
Adjacent roles you could pivot into.
site:jobindex.dk "[YOUR_ADJACENT_TITLE_1]" [YOUR_KEY_SKILL] [YOUR_CITY]
site:jobindex.dk "[YOUR_ADJACENT_TITLE_2]" [YOUR_KEY_SKILL] [YOUR_CITY]Priority 4: Broader Technical / Consulting
Wider net for general technical roles.
site:jobindex.dk [YOUR_KEY_SKILL] developer [YOUR_CITY]
site:linkedin.com/jobs "[YOUR_KEY_SKILL] developer" [YOUR_CITY]
site:jobindex.dk "technical consultant" [YOUR_DOMAIN] [YOUR_CITY]Location Filter
When evaluating results, verify the job location is within reasonable commute distance from your home. Define acceptable areas:
- [YOUR_CITY] and surrounding areas
- [ACCEPTABLE_AREA_1]
- [ACCEPTABLE_AREA_2]
- [BORDERLINE_AREA] (borderline - ~X min by transit)
- [TOO_FAR_AREA] (too far)
Date Filter
Only include jobs posted within the last 14 days, or with an application deadline that has not yet passed. If a posting date cannot be determined, include it but flag as "date unknown".
Adapting Queries
If the user specifies a focus area, select queries from the matching category and also generate 2-3 custom queries for that focus. For example:
- "/scrape [focus_area]" -> relevant category queries + custom focus-specific queries