b5a6f58fe326c4cb57b4ce1bd527da7aede37582
- Paginated HTML scraper (up to 6 pages, 400ms delay between requests) - Card-boundary-safe parsing to prevent field bleed across cards - Language filter: drops German (m/w/d, umlauts) and French (H/F, accents) titles - Software-role filter: requires title to contain a relevant tech term - Global deduplication by job ID across runs - 30-day recency filter via LinkedIn f_TPR parameter - CSV output: date_found, posted_at, search, title, company, link
linkme
Scrapes LinkedIn job listings into a local CSV. Run it daily, delete rows you've applied to.
Usage
bun fetch
No setup needed. Results are appended to jobs.csv — reruns are safe, already-seen jobs are skipped by ID.
Output
jobs.csv — one row per job:
| column | description |
|---|---|
date_found |
date you ran the fetch |
posted_at |
date the job was posted on LinkedIn |
search |
which search config matched it |
title |
job title |
company |
hiring company |
link |
canonical LinkedIn job URL |
Open in any spreadsheet app. Delete rows as you apply or dismiss.
How it works
- Paginated scraping — fetches up to 6 pages per search (150 jobs) with a 400 ms delay between pages to avoid rate limiting
- Card-boundary-safe parsing — each job card is isolated before extracting fields, preventing content from adjacent cards bleeding into company or date values
- Language filter — drops German (
m/w/d, umlauts, gender-marked vocabulary) and French (H/F, accented characters) job titles automatically - Software-role filter — requires the title to contain a relevant term (software, developer, data, AI, backend, devops, platform, architect, etc.) — eliminates aviation, mechanical, and pharma-process roles that match "Engineer" broadly
- Global deduplication — job IDs are indexed from the existing CSV on startup; jobs you've already seen are never re-added, even if you delete and re-run
- 30-day recency — only fetches jobs posted in the last month (
f_TPR=r2592000)
Configure searches
Edit config.ts:
const KEYWORDS = [
"Software Engineer",
"Full Stack Engineer",
"Data Engineer",
"AI Engineer",
"Ruby on Rails",
"Python",
// add or remove freely
].join(" OR ");
export const searches: SearchConfig[] = [
{
label: "Basel (city)",
keywords: KEYWORDS,
geoId: "103383283",
location: "Basel",
workType: ["onsite", "hybrid"],
timePosted: "month",
},
];
geoId values for the Basel area:
103383283— Basel (city)90009885— Basel Metropolitan Area107117530— Basel-Country
You can also paste any LinkedIn search URL directly as url: instead of building from filters.
Languages
TypeScript
91%
Shell
9%