Come raschiare gli annunci di lavoro di Indeed usando Python

Commenti: 0

Per chi cerca lavoro, per i datori di lavoro o per chiunque voglia monitorare le tendenze del mercato del lavoro, lo scraping dell'elenco dei lavori disponibili di Indeed può fornire informazioni utili. In questo particolare tutorial, combineremo Playwright per lo scraping del web e lxml per l'analisi del contenuto HTML, al fine di raccogliere i dettagli del lavoro, tra cui il titolo, il nome della società di selezione, la posizione, la descrizione del lavoro, il link all'annuncio di lavoro, e infine presenteremo i risultati salvando le informazioni in un file CSV.

Prequisiti

Per eseguire con successo lo scraping, è necessario installare le seguenti librerie Python.

Playwright per l'automazione del browser:


pip install playwright

lxml per l'analisi dell'HTML:


pip install lxml

pandas per salvare i dati in un file CSV:


pip install pandas

Installare il browser Playwright:

Dopo aver installato Playwright, eseguire questo comando per installare i binari dei browser necessari:


playwright install

Fase 1: Impostazione di Playwright per lo scraping web

Playwright consente di automatizzare e interagire con i browser web. Iniziamo impostando Playwright per lanciare un browser Chromium, visitare una pagina web ed estrarne il contenuto. Possiamo anche passare dei proxy attraverso Playwright.

Perché usare i proxy?

Spesso i siti web dispongono di misure di limitazione della velocità o di anti-scraping per bloccare le richieste ripetute dallo stesso indirizzo IP. I proxy consentono di:

  • Evitare il blocco degli IP: distribuire le richieste attraverso IP diversi per evitare il rilevamento.
  • Escludere la geolocalizzazione: accedere agli annunci di lavoro che potrebbero essere limitati in base alla posizione geografica.
  • Anonimato: nascondete il vostro IP reale e rimanete anonimi durante il processo di scraping.

import asyncio
from playwright.async_api import async_playwright

async def get_page_content(url):
    async with async_playwright() as p:
        browser = await p.chromium.launch(
            headless=False,
            proxy = {
                'server': '',
                'username': '',
                'password': ''
            }
        )  # Browser a testata
        page = await browser.new_page()
        await page.goto(url)
        
        # Estrarre il contenuto della pagina
        content = await page.content()
        
        await browser.close()  # Chiudere il browser una volta terminato
        return content


In questo codice, async_playwright lancia un browser intestato, naviga verso l'URL specificato e recupera il contenuto della pagina.

Parlare il contenuto HTML usando lxml

Successivamente, si analizzerà il contenuto della pagina per estrarre i dati significativi. A questo scopo si utilizza lxml, che fornisce un solido supporto per l'analisi e l'interrogazione del contenuto HTML tramite XPath.


from lxml import html

def parse_job_listings(content):
    # Analizzare il contenuto HTML
    parser = html.fromstring(content)
    
    # Estrarre ogni annuncio di lavoro utilizzando XPath
    job_posting = parser.xpath('//ul[@class="css-zu9cdh eu4oa1w0"]/li')
    
    jobs_data = []
    for element in job_posting[:-1]:  # Saltare l'ultimo elemento se si tratta di un annuncio o di un elemento irrilevante
        title = ''.join(element.xpath('.//h2/a/span/@title'))
        if title:
            link = ''.join(element.xpath('.//h2/a/@href'))
            location = ''.join(element.xpath('.//div[@data-testid="text-location"]/text()'))
            description = ', '.join(element.xpath('.//div[@class="css-9446fg eu4oa1w0"]/ul//li/text()'))
            company_name = ''.join(element.xpath('.//span[@data-testid="company-name"]/text()'))

            # Aggiungere i dati estratti all'elenco jobs_data
            jobs_data.append({
                'Title': title,
                'Link': f"https://www.indeed.com{link}",
                'Location': location,
                'Description': description,
                'Company': company_name
            })
    
    return jobs_data

Fase 2: Scraping degli annunci di lavoro

Ora che abbiamo impostato sia la fase di automazione del browser che quella di parsing, combiniamole per effettuare lo scraping degli annunci di lavoro dalla pagina di Indeed.

Spiegazione:

  • get_page_content(url): Recupera il contenuto della pagina utilizzando Playwright.
  • parse_job_listings(content): Analizza il contenuto utilizzando lxml ed estrae i dati del lavoro.
  • main(): Organizza il processo di scraping, recuperando i dati e salvandoli in un file CSV.

import pandas as pd

async def scrape_indeed_jobs(url):
    # Passo 1: ottenere il contenuto della pagina con Playwright
    content = await get_page_content(url)
    
    # Passo 2: analizzare l'HTML ed estrarre i dettagli del lavoro
    jobs_data = parse_job_listings(content)
    
    return jobs_data

# URL da raschiare
url = 'https://www.indeed.com/q-usa-jobs.html'

# Scraping e salvataggio dei dati
async def main():
    # Scrape i dati del lavoro dall'URL specificato
    jobs = await scrape_indeed_jobs(url)
    
    # Passo 3: salvare i dati in CSV con pandas
    df = pd.DataFrame(jobs)
    df.to_csv('indeed_jobs.csv', index=False)
    
    print("Data saved to indeed_jobs.csv")

# Eseguire la funzione principale
asyncio.run(main())

Fase 3: Aggiungere il supporto alla paginazione

Indeed impagina i suoi annunci di lavoro e si può facilmente estendere lo scraper per gestire più pagine. L'URL della pagina viene regolato utilizzando un parametro di query start, che aumenta di 10 per ogni nuova pagina.

Per migliorare la funzionalità dello scraper per la raccolta di dati da più pagine, è possibile implementare una funzione chiamata scrape_multiple_pages. Questa funzione modificherà l'URL di base regolando in modo incrementale il parametro start, consentendo l'accesso alle pagine successive. Procedendo sistematicamente attraverso ogni pagina, è possibile ampliare la portata e la quantità di dati raccolti, come ad esempio le offerte di lavoro, garantendo un set di dati più completo.


async def scrape_multiple_pages(base_url, pages=3):
    all_jobs = []
    
    for page_num in range(pages):
        # Aggiornare l'URL per la paginazione
        url = f"{base_url}&start={page_num * 10}"
        print(f"Scraping page: {url}")
        
        # Scrape i dati dei lavori da ogni pagina
        jobs = await scrape_indeed_jobs(url)
        all_jobs.extend(jobs)
    
    # Salvare tutti i lavori in CSV
    df = pd.DataFrame(all_jobs)
    df.to_csv('indeed_jobs_all_pages.csv', index=False)
    print("Data saved to indeed_jobs_all_pages.csv")

# Scrape di più pagine di annunci di lavoro
asyncio.run(scrape_multiple_pages('https://www.indeed.com/jobs?q=usa', pages=3))

Fase 4: personalizzare le query di ricerca di lavoro

Per mirare a titoli di lavoro o parole chiave specifiche nei vostri sforzi di scraping, dovrete configurare il parametro di ricerca della query nell'URL utilizzato da Indeed. Questa personalizzazione consente allo scraper di raccogliere dati specifici per particolari lavori o settori. Ad esempio, se state cercando posizioni di sviluppatore Python su http://www.indeed.com, dovrete regolare il parametro di ricerca in modo da includere "Python+sviluppatore" o parole chiave pertinenti.


query = "python+developer"
base_url = f"https://www.indeed.com/jobs?q={query}"
asyncio.run(scrape_multiple_pages(base_url, pages=3))

Modificando questo parametro in base alle vostre esigenze di raccolta dati, potete concentrare lo scraping su lavori specifici, migliorando la flessibilità e l'efficienza del vostro processo di raccolta dati. Questo approccio è particolarmente utile per adattarsi alle richieste dinamiche del mercato del lavoro.

Codice completo


import asyncio
from playwright.async_api import async_playwright
from lxml import html
import pandas as pd

# Passo 1: recuperare il contenuto della pagina con Playwright
async def get_page_content(url):
    async with async_playwright() as p:
        browser = await p.chromium.launch(
            headless=False
            proxy = {
                'server': '',
                'username': '',
                'password': ''
            }
        )  # Eseguire il browser in modalità guidata
        page = await browser.new_page()
        await page.goto(url, wait_until='networkidle')
        
        # Estrarre il contenuto della pagina
        content = await page.content()
        await browser.close()  # Chiudere il browser dopo l'uso
        return content

# Passo 2: analizzare il contenuto HTML con lxml
def parse_job_listings(content):
    # Analizzare l'HTML usando lxml
    parser = html.fromstring(content)
    
    # Selezionare singoli annunci di lavoro utilizzando XPath
    job_posting = parser.xpath('//ul[@class="css-zu9cdh eu4oa1w0"]/li')
    
    # Estrarre i dati del lavoro
    jobs_data = []
    for element in job_posting[:-1]:
        title = ''.join(element.xpath('.//h2/a/span/@title'))
        if title:
            link = ''.join(element.xpath('.//h2/a/@href'))
            location = ''.join(element.xpath('.//div[@data-testid="text-location"]/text()'))
            description = ', '.join(element.xpath('.//div[@class="css-9446fg eu4oa1w0"]/ul//li/text()'))
            company_name = ''.join(element.xpath('.//span[@data-testid="company-name"]/text()'))

            # Aggiungere i dati estratti all'elenco jobs_data
            jobs_data.append({
                'Title': title,
                'Link': f"https://www.indeed.com{link}",
                'Location': location,
                'Description': description,
                'Company': company_name
            })
    
    return jobs_data

# Passo 3: Scraping delle offerte di lavoro di Indeed per una singola pagina
async def scrape_indeed_jobs(url):
    # Ottenere il contenuto della pagina con Playwright
    content = await get_page_content(url)
    
    # Analizzare l'HTML ed estrarre i dati del lavoro
    jobs_data = parse_job_listings(content)
    
    return jobs_data

# Passo 4: Gestione della paginazione e scraping di più pagine
async def scrape_multiple_pages(base_url, query, pages=3):
    all_jobs = []
    
    for page_num in range(pages):
        # Update the URL to handle pagination and add the search query
        url = f"{base_url}?q={query}&start={page_num * 10}"
        print(f"Scraping page: {url}")
        
        # Lavori di scraping per la pagina corrente
        jobs = await scrape_indeed_jobs(url)
        all_jobs.extend(jobs)
    
    # Salvare tutti i lavori in un file CSV
    df = pd.DataFrame(all_jobs)
    df.to_csv(f'indeed_jobs_{query}.csv', index=False)
    print(f"Data saved to indeed_jobs_{query}.csv")

# Funzione per eseguire lo scraper con l'input di una query dinamica
async def run_scraper():
    # Passo 5: Chiedere all'utente la query di input e il numero di pagine da scrapare
    query = input("Enter the job title or keywords to search (e.g., python+developer): ")
    pages = int(input("Enter the number of pages to scrape: "))
    
    # Eseguire lo scraping di lavori su più pagine in base alla query
    base_url = 'https://www.indeed.com/jobs'
    await scrape_multiple_pages(base_url, query, pages)

# Eseguire il raschietto
asyncio.run(run_scraper())

Per garantire un processo di scraping senza intoppi e ridurre il rischio di blocchi e di apparizioni di CAPTCHA, è fondamentale scegliere il server proxy giusto. L'opzione più ottimale per lo scraping è rappresentata dai proxy ISP, che offrono un'elevata velocità e stabilità di connessione, oltre a un alto fattore di fiducia che li rende raramente bloccati dalle piattaforme. Questo tipo di proxy è statico, quindi per lo scraping su larga scala è necessario creare un pool di proxy ISP e configurare la rotazione degli IP per cambiarli regolarmente. Un'opzione alternativa è rappresentata dai proxy residenziali, che sono dinamici e hanno la più ampia copertura geografica rispetto ad altri tipi di server proxy.

Commenti:

0 Commenti