# Analyse du marché de skis d'occasion - Freeglisse.com

> Web scraping et dashboard Power BI pour analyser le positionnement produit de Freeglisse.com, leader français de la revente de skis d'occasion.

Publié le 12 avril 2026
Source : https://cyril-gervais.com/projets/analyse-marche-ski-occasion-freeglisse/

---
## Contexte du projet

**Freeglisse.com** se positionne comme le site leader de la revente de skis d'occasion en France. La plateforme propose un large catalogue d'équipements, catégorisés par type d'usage, niveau de qualité, marque, etc.

L'objectif de ce **cas pratique, réalisé dans le cadre de ma formation en analyse de données,** est de collecter les produits disponibles à la revente puis de fournir un dashboard Power BI d'analyse afin d'évaluer le positionnement et l'offre produit du site.

*[Image : Page de vente des skis d'occasion sur Freeglisse.com - Aperçu de la structure de la page de vente des skis d'occasion sur Freeglisse.com]*

## Méthodologie : web scraping avec Python 

### 1. Configuration et dépendances

Le projet utilise un ensemble de librairies Python :

| Librairie | Rôle |
|---|---|
| **requests** / **httpx** | Envoi des requêtes HTTP vers le site (requests pour les pages détail, httpx pour les listings) |
| **BeautifulSoup** | Analyse du HTML des fiches produits — extraction fine des prix, marques et caractéristiques |
| **Selectolax** | Parsing rapide des pages de listing pour extraire les URLs produits (plus performant que BeautifulSoup sur du HTML volumineux) |
| **Pandas** | Structuration des données collectées en DataFrame et export CSV |
| **tqdm** | Affichage de barres de progression pendant la collecte |

Le fichier `config.py` centralise les paramètres du scraping : les URLs de base pour chaque catégorie de qualité et les en-têtes HTTP qui simulent un navigateur classique afin que les requêtes ne soient pas bloquées par le serveur.

```python
BASE_URLS = {
    "A": "https://freeglisse.com/.../etat_du_materiel-qualite_a?page=",
    "B": "https://freeglisse.com/.../etat_du_materiel-qualite_b?page=",
    "C": "https://freeglisse.com/.../etat_du_materiel-qualite_c?page=",
}

HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ..."
}
```

### 2. Collecte des URLs produits

La première étape consiste à **inventorier toutes les pages produits du site**. Le catalogue étant paginé, le script parcourt les pages une par une jusqu'à rencontrer le message « Aucun produit disponible », qui signale la fin du catalogue :

```python
def get_all_urls(page):
    page_number = 1
    not_last_page = True

    while not_last_page:
        url = f"{page}{page_number}"
        response = requests.get(url, headers=config.HEADERS)

        if "Aucun produit disponible pour le moment" in response.text:
            not_last_page = False  # Fin du catalogue atteinte
        else:
            page_number += 1
```

Une fois toutes les pages listées, le script extrait l'URL de chaque fiche produit grâce à **Selectolax**, un parser HTML rapide particulièrement adapté au traitement de pages volumineuses :

```python
    for url in tqdm(url_list, desc="Parsing product pages"):
        html = HTMLParser(httpx.get(url).text)
        products = html.css('article[data-id-product]')

        for product in products:
            link = product.css_first('a.thumbnail.product-thumbnail')
            url_products_list.append(link.attributes['href'])
```

Ce processus est exécuté **trois fois**, une pour chaque niveau de qualité (A, B et C), afin de couvrir l'intégralité du catalogue.

### 3. Extraction des données produits

Pour chaque URL collectée, le script accède à la fiche produit et en extrait les informations clés avec **BeautifulSoup**, mieux adapté ici car les fiches contiennent une structure HTML plus complexe (listes de caractéristiques imbriquées) :

```python
def get_details(url_list):
    for url in tqdm(url_list, desc="Fetching product details"):
        soup = BeautifulSoup(requests.get(url).content, "html.parser")

        # Prix, identifiant, titre, marque
        price = soup.select_one('.current-price-value').text.strip()
        title = soup.find('h1').text.strip()
        brand = soup.find('img', {'class': 'manufacturer-logo'}).get('alt')

        # Caractéristiques techniques (taille, rayon, poids...)
        features = soup.find("dl", class_="data-sheet")
        for tag in features.find_all(["dt", "dd"]):
            # Les <dt> contiennent les intitulés,
            # les <dd> les valeurs correspondantes
```

Chaque appel gère les **cas d'erreur** (produit sans prix, sans marque...) via des blocs `try/except` pour garantir la robustesse de la collecte sur l'ensemble du catalogue.

### 4. Structuration et export des données

Les données des trois catégories de qualité sont fusionnées dans un **DataFrame Pandas** unique, enrichi d'une colonne `Qualité` pour conserver la segmentation :

| Champ | Description |
|---|---|
| `Product ID` | Identifiant unique du produit |
| `Title` | Nom du produit |
| `Price` | Prix de vente |
| `Brand` | Marque |
| `Qualité` | Niveau de qualité (A, B ou C) |
| `Caractéristiques` | Champs dynamiques extraits des fiches produits (taille, rayon, etc.) |

```python
for quality, url_list in zip(["Qualité A", "Qualité B", "Qualité C"], urls):
    df = get_details(url_list)
    df["Qualité"] = quality
    dfs.append(df)

df_final = pd.concat(dfs, axis=0)
df_final.to_csv("freeglisse_export.csv", index=False)
```

Le fichier CSV final sert de **source de données pour le dashboard Power BI**.

 [Voir le code source du projet sur GitHub](https://github.com/cyrilgrv/freeglisse-olist)

### Dashboard Power BI

Les données exportées en CSV alimentent un dashboard Power BI interactif permettant d'explorer le catalogue selon plusieurs axes : répartition par marque, distribution des prix, segmentation par qualité et analyse croisée des caractéristiques produits.

 [Voir le tableau de bord en plein écran](https://app.powerbi.com/view?r=eyJrIjoiODcxMDQzZWUtMmQ3Yy00OTI2LWJlZGMtNTljNGQ5ZjczZDUwIiwidCI6IjJkNjhkYjFhLTNmY2QtNDZjMi1iNDNiLTlhYjE4NjU1NzY1NyIsImMiOjEwfQ%3D%3D)

<iframe
  title="Dashboard Power BI — Freeglisse"
  width="100%"
  height="500"
  src="https://app.powerbi.com/view?r=eyJrIjoiODcxMDQzZWUtMmQ3Yy00OTI2LWJlZGMtNTljNGQ5ZjczZDUwIiwidCI6IjJkNjhkYjFhLTNmY2QtNDZjMi1iNDNiLTlhYjE4NjU1NzY1NyIsImMiOjEwfQ%3D%3D"
  frameborder="0"
  allowFullScreen={true}
  style="border: none; border-radius: 8px;"
></iframe>
