Comment récupérer les offres d'emploi d'Indeed en utilisant Python

Commentaires: 0

Pour les chasseurs d'emploi, les employeurs ou toute personne surveillant les tendances du marché de l'emploi, l'analyse de la liste des emplois disponibles d'Indeed peut fournir des informations utiles. Dans ce tutoriel, nous allons combiner Playwright pour le web scraping et lxml pour l'analyse du contenu HTML afin de collecter les détails de l'emploi, y compris son titre, le nom de l'entreprise qui recrute, le lieu, la description de l'emploi, le lien de l'offre d'emploi, et enfin présenter les résultats en enregistrant les informations dans un fichier CSV.

Prérequis

Pour réussir le scraping, les bibliothèques Python suivantes doivent être installées.

Playwright pour l'automatisation du navigateur :


pip install playwright

lxml pour l'analyse du langage HTML :


pip install lxml

pandas pour enregistrer les données dans un fichier CSV :


pip install pandas

Installer les navigateurs Playwright:

Après avoir installé Playwright, exécutez cette commande pour installer les binaires nécessaires au navigateur :


playwright install

Etape 1 : Configuration de Playwright pour le web scraping

Playwright vous permet d'automatiser et d'interagir avec les navigateurs web. Nous commençons par configurer Playwright pour lancer un navigateur Chromium, visiter une page web et en extraire le contenu. Ici, nous pouvons également passer des proxys à travers le playwright.

Pourquoi utiliser des proxys?

Les sites web ont souvent mis en place des mesures de limitation du débit ou d'anti-scraping afin de bloquer les requêtes répétées provenant de la même adresse IP. Les proxys vous permettent de :

  • Éviter le blocage d'IP : distribuez vos demandes par le biais de différentes IP pour éviter d'être détecté.
  • Contourner la géolocalisation : accédez aux offres d'emploi susceptibles d'être restreintes en fonction de la localisation géographique.
  • Anonymat : masquez votre IP réelle et restez anonyme pendant le processus de 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': ''
            }
        )  # Navigateur à tête chercheuse
        page = await browser.new_page()
        await page.goto(url)
        
        # Extraire le contenu de la page
        content = await page.content()
        
        await browser.close()  # Fermez le navigateur une fois que vous avez terminé
        return content


Dans ce code, async_playwright lance un navigateur à en-tête, navigue jusqu'à l'URL spécifiée et récupère le contenu de la page.

Analyse du contenu HTML à l'aide de lxml

Ensuite, nous analyserons le contenu de la page pour en extraire des données significatives. lxml est utilisé à cette fin parce qu'il fournit un support robuste pour l'analyse et l'interrogation du contenu HTML à l'aide de XPath.


from lxml import html

def parse_job_listings(content):
    # Analyse du contenu HTML
    parser = html.fromstring(content)
    
    # Extraire chaque offre d'emploi à l'aide de XPath
    job_posting = parser.xpath('//ul[@class="css-zu9cdh eu4oa1w0"]/li')
    
    jobs_data = []
    for element in job_posting[:-1]:  # Sauter le dernier élément s'il s'agit d'une publicité ou d'un élément non pertinent
        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()'))

            # Ajouter les données extraites à la liste jobs_data
            jobs_data.append({
                'Title': title,
                'Link': f"https://www.indeed.com{link}",
                'Location': location,
                'Description': description,
                'Company': company_name
            })
    
    return jobs_data

Etape 2 : Récupérer les offres d'emploi

Maintenant que nous avons mis en place les étapes d'automatisation du navigateur et d'analyse, combinons-les pour récupérer les offres d'emploi de la page Indeed.

Explication :

  • get_page_content(url): Récupère le contenu de la page à l'aide de Playwright.
  • parse_job_listings(content): Analyse le contenu à l'aide de lxml et extrait les données relatives à l'emploi.
  • main(): Orchestre le processus de scraping, récupère les données et les enregistre dans un fichier CSV.

import pandas as pd

async def scrape_indeed_jobs(url):
    # Étape 1 : Obtenir le contenu de la page à l'aide de Playwright
    content = await get_page_content(url)
    
    # Étape 2 : Analyse du code HTML et extraction des détails de l'emploi
    jobs_data = parse_job_listings(content)
    
    return jobs_data

# URL à récupérer
url = 'https://www.indeed.com/q-usa-jobs.html'

# Récupérer et enregistrer des données
async def main():
    # Récupérer les données d'un travail à partir de l'URL spécifiée
    jobs = await scrape_indeed_jobs(url)
    
    # Étape 3 : Enregistrer les données au format CSV à l'aide de pandas
    df = pd.DataFrame(jobs)
    df.to_csv('indeed_jobs.csv', index=False)
    
    print("Data saved to indeed_jobs.csv")

# Exécuter la fonction principale
asyncio.run(main())

Etape 3 : Ajouter la prise en charge de la pagination

Indeed pagine ses offres d'emploi et vous pouvez facilement étendre le scraper pour qu'il prenne en charge plusieurs pages. L'URL de la page est ajustée à l'aide d'un paramètre de requête start, qui s'incrémente de 10 pour chaque nouvelle page.

Pour améliorer la fonctionnalité de votre scraper afin de collecter des données à partir de plusieurs pages, vous pouvez mettre en œuvre une fonction appelée scrape_multiple_pages. Cette fonction modifiera l'URL de base en ajustant progressivement le paramètre "start", ce qui permettra d'accéder aux pages suivantes. En progressant systématiquement sur chaque page, vous pouvez élargir la portée et la quantité des données collectées, telles que les offres d'emploi, ce qui permet d'obtenir un ensemble de données plus complet.


async def scrape_multiple_pages(base_url, pages=3):
    all_jobs = []
    
    for page_num in range(pages):
        # Mise à jour de l'URL pour la pagination
        url = f"{base_url}&start={page_num * 10}"
        print(f"Scraping page: {url}")
        
        # Récupérer les données relatives à l'emploi sur chaque page
        jobs = await scrape_indeed_jobs(url)
        all_jobs.extend(jobs)
    
    # Enregistrer tous les emplois au format 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")

# Récupérer plusieurs pages d'offres d'emploi
asyncio.run(scrape_multiple_pages('https://www.indeed.com/jobs?q=usa', pages=3))

Etape 4 : Personnaliser les requêtes de recherche d'emploi

Pour cibler des titres d'emploi ou des mots-clés spécifiques dans vos efforts de scrapping, vous devrez configurer le paramètre de recherche de la requête dans l'URL utilisée par Indeed. Cette personnalisation permet au scraper de collecter des données spécifiques à des emplois ou des secteurs particuliers. Par exemple, si vous recherchez des postes de développeur Python sur http://www.indeed.com, vous devez ajuster le paramètre de recherche pour inclure "Python+développeur" ou des mots-clés pertinents.


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

En modifiant ce paramètre en fonction de vos besoins en matière de collecte de données, vous pouvez concentrer votre scraping sur des emplois spécifiques, ce qui améliore la flexibilité et l'efficacité de votre processus de collecte de données. Cette approche est particulièrement utile pour s'adapter aux demandes dynamiques du marché de l'emploi.

Code complet


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

# Étape 1 : Récupérer le contenu de la page à l'aide de Playwright
async def get_page_content(url):
    async with async_playwright() as p:
        browser = await p.chromium.launch(
            headless=False
            proxy = {
                'server': '',
                'username': '',
                'password': ''
            }
        )  # Exécuter le navigateur en mode tête
        page = await browser.new_page()
        await page.goto(url, wait_until='networkidle')
        
        # Extraire le contenu de la page
        content = await page.content()
        await browser.close()  # Fermer le navigateur après utilisation
        return content

# Étape 2 : Analyse du contenu HTML à l'aide de lxml
def parse_job_listings(content):
    # Analyse du code HTML à l'aide de lxml
    parser = html.fromstring(content)
    
    # Sélectionner des offres d'emploi individuelles à l'aide de XPath
    job_posting = parser.xpath('//ul[@class="css-zu9cdh eu4oa1w0"]/li')
    
    # Extraire les données relatives à l'emploi
    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()'))

            # Ajouter les données extraites à la liste jobs_data
            jobs_data.append({
                'Title': title,
                'Link': f"https://www.indeed.com{link}",
                'Location': location,
                'Description': description,
                'Company': company_name
            })
    
    return jobs_data

# Étape 3 : Récupérer les offres d'emploi d'Indeed pour une seule page
async def scrape_indeed_jobs(url):
    # Obtenir le contenu de la page à l'aide de Playwright
    content = await get_page_content(url)
    
    # Analyse du code HTML et extraction des données relatives aux emplois
    jobs_data = parse_job_listings(content)
    
    return jobs_data

# Étape 4 : Gérer la pagination et récupérer plusieurs pages
async def scrape_multiple_pages(base_url, query, pages=3):
    all_jobs = []
    
    for page_num in range(pages):
        # Mettre à jour l'URL pour gérer la pagination et ajouter la requête de recherche
        url = f"{base_url}?q={query}&start={page_num * 10}"
        print(f"Scraping page: {url}")
        
        # Récupérer les travaux pour la page en cours
        jobs = await scrape_indeed_jobs(url)
        all_jobs.extend(jobs)
    
    # Enregistrer tous les travaux dans un fichier 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")

# Fonction permettant d'exécuter le scraper avec une entrée de requête dynamique
async def run_scraper():
    # Étape 5 : Demander à l'utilisateur de saisir sa requête et le nombre de pages à récupérer
    query = input("Enter the job title or keywords to search (e.g., python+developer): ")
    pages = int(input("Enter the number of pages to scrape: "))
    
    # Scraper les travaux sur plusieurs pages en fonction de la requête
    base_url = 'https://www.indeed.com/jobs'
    await scrape_multiple_pages(base_url, query, pages)

#  Faire fonctionner le grattoir
asyncio.run(run_scraper())

Pour garantir un processus de scraping fluide et réduire le risque de blocages et d'apparitions de CAPTCHA, il est essentiel de choisir le bon serveur proxy. L'option la plus optimale pour le scraping sont les proxys des FAI, qui offrent une vitesse élevée et une stabilité de connexion, ainsi qu'un facteur de confiance élevé, ce qui fait qu'ils sont rarement bloqués par les plateformes. Ce type de proxy est statique, donc pour le scraping à grande échelle, il est nécessaire de créer un pool de proxys ISP et de configurer la rotation des IP pour qu'elles changent régulièrement. Une autre option serait les proxys résidentiels, qui sont dynamiques et ont la couverture géographique la plus large par rapport aux autres types de serveurs proxy.

Commentaires:

0 Commentaires