Dev.to · 3 min read

Automate your job search: a daily LinkedIn jobs pipeline in Python

Automate your job search: a daily LinkedIn jobs pipeline in Python

Job hunting has a timing problem that nobody warns you about. A posting goes up. For the first few hours it has a handful of applicants. By day three it has two hundred, a recruiter has stopped reading carefully, and your carefully tailored application is row 187 in an ATS. You cannot control how good the other 186 candidates are. You can control whether you were row 8 instead. That is an automation problem, and it takes about forty lines of Python. The two filters that actually matter LinkedIn's job search has a lot of knobs. For this purpose, two of them do most of the work: Posted in the last 24 hours. Anything older is already contested. Under 10 applicants. LinkedIn exposes this, and it is the single best proxy for "you will actually be read." Everything else — seniority, remote, job type — narrows the funnel to roles you would actually take. But the two above are what turn a job feed into an edge. Checking that by hand every morning is exactly the kind of thing you stop doing on day four. So let's not do it by hand. One call for the data I am using an Apify Actor that queries LinkedIn's job search and returns structured results. The endpoint below starts a run, waits, and hands back the rows — no polling loop, no login, no cookie to extract from your browser. curl -X POST \ "https://api.apify.com/v2/acts/data_pool~linkedin-jobs-scraper/run-sync-get-dataset-items" \ -H "Authorization: Bearer $APIFY_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "keywords": ["backend engineer", "platform engineer"], "maxItems": 100, "location": "Berlin, Germany", "workplaceType": ["remote", "hybrid"], "datePosted": "24h", "sortBy": "date", "under10Applicants": true }' Each keyword runs as its own search, and results are de-duplicated across them, so overlapping search terms do not produce duplicate rows. What comes back { "jobId": "4012345678", "jobUrl": "https://www.linkedin.com/jobs/view/4012345678/", "title": "Senior Backend Engineer", "location": "Berlin, Germany", "workplaceType": "hybrid", "listedAtIso": "2026-08-11T09:12:00Z", "easyApply": true, "fewApplicants": true, "isPromoted": false, "company": { "name": "Acme GmbH", "profileUrl": "https://www.linkedin.com/company/acme-gmbh" }, "insights": ["Actively hiring"], "matchedKeyword": "backend engineer" } Three fields deserve attention: jobId is stable across runs. That is your deduplication key — without it, a daily job will keep showing you Monday's postings all week. workplaceType comes back as a raw enum (on_site, remote, hybrid), not a pretty label. Map it before it reaches a human. isPromoted tells you the company paid to boost the listing. Not automatically bad, but a promoted post that is three weeks old is a different signal from a fresh organic one. The daily script This is the whole thing: fetch, drop anything seen before, print a digest. import json import os import pathlib import requests ACTOR = "data_pool~linkedin-jobs-scraper" URL = f"https://api.apify.com/v2/acts/{ACTOR}/run-sync-get-dataset-items" SEEN = pathlib.Path("seen_jobs.json") WORKPLACE = {"on_site": "On-site", "remote": "Remote", "hybrid": "Hybrid"} SEARCH = { "keywords": ["backend engineer", "platform engineer"], "maxItems": 100, "location": "Berlin, Germany", "workplaceType": ["remote", "hybrid"], "datePosted": "24h", "sortBy": "date", "under10Applicants": True, } def fetch_jobs(): resp = requests.post( URL, headers={"Authorization": f"Bearer {os.environ['APIFY_TOKEN']}"}, json=SEARCH, timeout=300, ) resp.raise_for_status() return resp.json() def main(): seen = set(json.loads(SEEN.read_text())) if SEEN.exists() else set() fresh = [] for job in fetch_jobs(): job_id = job.get("jobId") if not job_id or job_id in seen: continue seen.add(job_id) fresh.append(job) for job in fresh: company = (job.get("company") or {}).get("name", "unknown") flags = [] if job.get("easyApply"): flags.append("Easy Apply") if job.get("fewApplicants"): flags.append("

This is a summary aggregated from Dev.to. Read the complete article on the original site:

Read full article at Dev.to

More Programming & Dev News