Come costruire un aggregatore di offerte di lavoro: fonti, deduplica e freschezza
Un buon aggregatore di offerte di lavoro è composto da tre problemi ingegneristici: dove trovare gli annunci, come deduplicarli e come mantenerli aggiornati. Risolvi questi problemi e il scraping diventa la parte facile — ecco il progetto.
Un aggregatore di offerte di lavoro è un motore di ricerca per annunci di lavoro: raccoglie annunci da molte fonti e li mostra in un unico posto. Le parti difficili non sono le richieste HTTP — sono scegliere le fonti giuste, deduplicare lo stesso lavoro che appare su cinque siti e mantenere tutto fresco in modo da non mostrare ruoli già occupati il mese scorso. Se riesci in questi tre aspetti, hai un prodotto difendibile; se fallisci, hai un feed stantio e pieno di duplicati che erode la fiducia. Questa guida è il progetto ingegneristico: mix di fonti, deduplica canonica, freschezza, il verticale SERP delle offerte di lavoro e le linee legali da rispettare. È informativa, non un consiglio legale.
Fonte livello 1: endpoint pubblici degli ATS
I dati di lavoro più puliti su internet non si trovano sui portali di lavoro — si trovano sulle pagine delle carriere aziendali alimentate dai sistemi di tracciamento delle candidature, la maggior parte dei quali espone JSON strutturato. Greenhouse, Lever, Ashby, BambooHR, iCIMS, Paylocity e Workday offrono tutti annunci che puoi richiedere direttamente, senza parsing HTML. Un aggregatore open-source che estrae da tutti e sette li recupera in parallelo e regola il numero di lavoratori ai limiti di velocità di ciascuna piattaforma — circa 50 concorrenti per Workday, 30 per Greenhouse/Lever/iCIMS, 10 per BambooHR e 5 per i limitatori più stretti. Questo livello ti offre titoli canonici, località, fasce salariali e URL per candidarsi direttamente dal datore di lavoro, il che lo rende la spina dorsale di qualsiasi aggregatore serio.
import httpx
# Greenhouse exposes a public board JSON endpoint per company slug
def fetch_greenhouse(slug: str) -> list[dict]:
url = f"https://boards-api.greenhouse.io/v1/boards/{slug}/jobs?content=true"
r = httpx.get(url, timeout=20)
r.raise_for_status()
jobs = r.json().get("jobs", [])
return [{
"source": "greenhouse",
"external_id": str(j["id"]),
"title": j["title"],
"company": slug,
"location": (j.get("location") or {}).get("name"),
"apply_url": j["absolute_url"],
"updated_at": j.get("updated_at"),
} for j in jobs]
rows = fetch_greenhouse("examplecompany")
print(len(rows), "roles")
Per trovare le aziende da sondare, raccogli gli slug degli ATS su larga scala da un indice web piuttosto che a mano — scansionando gli archivi URL di Common Crawl per modelli di dominio ATS possono emergere decine di migliaia di identificatori aziendali. Quella scansione di scoperta è essa stessa un lavoro di scraping; instradala attraverso un pool di proxy datacenter poiché l'indice è tollerante e la velocità conta più della reputazione IP lì.
Fonte livello 2: il verticale SERP delle offerte di lavoro
I feed degli ATS mancano di tutto ciò che viene pubblicato solo sui siti aggregatori, sui portali regionali o sull'esperienza di lavoro di Google. Il modo efficiente per coprire quella lunga coda senza fare scraping di una dozzina di portali individualmente è il verticale SERP delle offerte di lavoro — una query strutturata che restituisce le offerte che Google mostra per un ruolo e una località, già normalizzate. La nostra SERP API espone un verticale delle offerte di lavoro insieme a notizie, immagini e shopping, quindi puoi estrarre gli annunci di ruolo per parola chiave e geo come JSON e integrarli nello stesso pipeline:
import httpx
def fetch_jobs_serp(query: str, location: str) -> list[dict]:
r = httpx.get(
"https://api.quantumproxies.io/serp",
params={"engine": "google_jobs", "q": query,
"location": location, "api_key": "QP_API_KEY"},
timeout=30,
)
jobs = r.json().get("jobs", [])
return [{
"source": "jobs_serp",
"external_id": j.get("job_id"),
"title": j.get("title"),
"company": j.get("company_name"),
"location": j.get("location"),
"apply_url": (j.get("apply_options") or [{}])[0].get("link"),
} for j in jobs]
serp_rows = fetch_jobs_serp("react developer", "Austin, TX")
Esegui la stessa query nelle città target secondo un programma e avrai una copertura geografica che nessun singolo feed ATS fornisce. Poiché i risultati SERP cambiano in base alla località, geo-targetizza ogni query — il nostro post su come funziona lo scraping SERP nel 2026 copre le meccaniche geo e di paginazione.
Estrai il verticale delle offerte di lavoro dalla SERP API

Deduplica con chiave canonica
Lo stesso lavoro appare regolarmente sul sito aziendale, su due aggregatori e su una scheda di lavoro di Google. Mostrarlo quattro volte è il modo più veloce per sembrare difettoso. La soluzione standard è una chiave canonica: normalizza e hash la combinazione di titolo del lavoro, azienda, località e — quando disponibile — l'ID esterno del lavoro della fonte. Converti in minuscolo, rimuovi la punteggiatura e comprimi gli spazi bianchi prima di fare l'hash in modo che "Sr. Software Engineer" e "senior software engineer" si uniscano.
import re, hashlib
def canonical_key(job: dict) -> str:
def norm(s):
return re.sub(r"[^a-z0-9]+", " ", (s or "").lower()).strip()
basis = "|".join([
norm(job.get("title")),
norm(job.get("company")),
norm(job.get("location")),
(job.get("external_id") or ""),
])
return hashlib.sha1(basis.encode()).hexdigest()
def dedupe(rows: list[dict]) -> list[dict]:
seen, out = set(), []
for job in rows:
k = canonical_key(job)
if k not in seen:
seen.add(k)
out.append(job)
return out
La freschezza è una caratteristica, non un ripensamento
La credibilità di un portale di lavoro è la sua freschezza. Due meccaniche la mantengono onesta: recupera ogni fonte secondo un programma (ogni ora per i feed ATS ad alto volume, ogni giorno per la lunga coda) e elimina tutto ciò che non hai rivisto in una finestra mobile — 30 giorni è un valore predefinito sensato, più breve per i mercati in rapido movimento. Traccia un timestamp dell'ultima visualizzazione per fonte e un conteggio giornaliero in modo da poter individuare quando una fonte si rompe silenziosamente; un aggregatore che monitora il proprio volume può aprire un avviso nel momento in cui i numeri di una piattaforma crollano. La nostra nota su eseguire scraper come software di produzione copre la pianificazione, il rilevamento delle derive e l'allerta.
Le linee legali da rispettare
I dati di lavoro sono dove la legge sullo scraping diventa reale, perché gli annunci possono contenere dati personali (nomi dei reclutatori, dettagli di contatto) e descrizioni dettagliate sono soggette a copyright. L'autorità francese per la protezione dei dati ha multato l'azienda KASPR di €240.000 per aver fatto scraping dei dati di contatto di LinkedIn senza il giusto consenso; le sanzioni GDPR possono raggiungere i €20 milioni o il 4% del fatturato globale, e i danni da copyright hanno raggiunto i $150.000 per opera nei casi statunitensi. La postura più sicura è strutturale: preferisci i feed ATS autorizzati e il SERP delle offerte di lavoro rispetto al brute-forcing dei portali protetti da login, memorizza campi fattuali (titolo, azienda, località) piuttosto che ripubblicare descrizioni complete soggette a copyright, e rimuovi i dati personali di cui non hai bisogno. La nostra panoramica sulla legalità dello scraping web nel 2026 e la saga di conformità di LinkedIn approfondiscono ulteriormente.

Dove si inseriscono i proxy
Il livello ATS raramente necessita di IP residenziali, ma la scansione di scoperta, il verticale SERP e qualsiasi scraping diretto dei portali sì — Google e i portali più grandi limitano la velocità per IP e variano i risultati in base alla geo. Instrada quelli attraverso proxy residenziali rotanti con rotazione per richiesta e targeting geo in modo che ogni query della città provenga da una località corrispondente. Mantieni i livelli separati: datacenter economico per l'indice tollerante, residenziale per i target sensibili.
Domande frequenti
Cos'è un aggregatore di offerte di lavoro?
È un motore di ricerca per annunci di lavoro che raccoglie annunci da molte fonti — pagine delle carriere aziendali, piattaforme ATS, altri portali e il SERP delle offerte di lavoro — li normalizza in uno schema unico, rimuove i duplicati e li presenta ai cercatori di lavoro in un unico luogo ricercabile. Il lavoro ingegneristico riguarda le fonti, la deduplicazione e la freschezza, non solo lo scraping.
Come deduplicare gli annunci di lavoro da più fonti?
Costruisci una chiave canonica normalizzando e facendo l'hash del titolo del lavoro, dell'azienda, della località e dell'ID esterno del lavoro della fonte. Converti in minuscolo, rimuovi la punteggiatura e comprimi gli spazi bianchi prima in modo che le varianti ortografiche si uniscano. Mantieni la prima occorrenza e elimina i corrispondenti. Questo cattura lo stesso ruolo che appare sul sito del datore di lavoro, sugli aggregatori e su Google jobs.
È legale fare scraping dei portali di lavoro?
Dipende dalla fonte, dai dati e dalla tua giurisdizione. I campi di elenchi fattuali pubblici sono a rischio minore rispetto ai dati personali o alle descrizioni complete soggette a copyright, e bypassare i muri di login aumenta l'esposizione in stile CFAA. I feed ATS autorizzati e il SERP delle offerte di lavoro sono le rotte più pulite. Le aziende sono state pesantemente multate per lo scraping di dati personali — ottieni consulenza legale per l'uso commerciale.
Quanto dovrebbero essere freschi i dati aggregati delle offerte di lavoro?
Recupera le fonti ad alto volume come i feed ATS ogni ora e la lunga coda ogni giorno, quindi elimina qualsiasi annuncio che non hai rivisto entro una finestra mobile — 30 giorni è un valore predefinito comune. Traccia un timestamp dell'ultima visualizzazione per lavoro e monitora il volume per fonte in modo da catturare una fonte rotta prima che gli utenti vedano ruoli stantii.
Tratta l'aggregazione come tre problemi — fonti, deduplica, freschezza — e lo scraping diventa un dettaglio di supporto. Inizia con feed ATS puliti e il verticale SERP delle offerte di lavoro, deduplica su una chiave canonica, elimina in modo aggressivo e mantieni le scansioni sensibili su IP residenziali rotanti. Questa è la differenza tra un prodotto di cui le persone si fidano e un cimitero di link morti.