Extraire eBay avec Python : un code qui fonctionne vraiment

Dernière mise à jour le April 16, 2026

La plupart des tutoriels sur l’extraction de données eBay ont une durée de vie d’environ trois mois. Je le sais, parce que l’équipe de Thunderbit voit régulièrement des développeurs enchaîner des extraits de code cassés, des sélecteurs CSS obsolètes et des dépôts GitHub “fonctionnels” qui ont discrètement cessé de marcher deux refontes eBay plus tôt.

eBay héberge — le plus grand ensemble de données sur les prix longue traîne du web ouvert après Amazon. Ces données alimentent tout, de la tarification pour les revendeurs à l’intelligence concurrentielle. Mais y accéder de manière programmatique reste une cible mouvante : l’interface React d’eBay change les noms de classes CSS, les tests A/B exposent des structures DOM différentes selon les utilisateurs, et Akamai Bot Manager se place entre vous et le HTML. Ce guide vous donne du code Python qui fonctionne aujourd’hui, explique pourquoi les scrapers cassent afin que vous puissiez en construire de plus robustes, compare honnêtement l’API eBay et le scraping, et présente une issue sans code quand Python ne vaut pas la mise en place.

Que signifie extraire eBay avec Python ?

Extraire des données eBay avec Python consiste à écrire des scripts qui téléchargent automatiquement les pages eBay, analysent le HTML (ou le JSON caché), puis en extraient des données structurées — titres, prix, infos vendeur, dates de vente, variantes — dans un format réellement exploitable, comme un CSV, un tableur ou une base de données.

Vous pouvez extraire plusieurs types de pages eBay :

  • Résultats de recherche (par exemple toutes les annonces “AirPods Pro”)
  • Pages produit individuelles (caractéristiques complètes, images, infos vendeur)
  • Annonces vendues/terminées (prix et dates de transaction réels)
  • Profils vendeurs et avis

Python est le langage de référence pour ce travail. Son écosystème — Requests, BeautifulSoup, lxml, pandas — permet de récupérer facilement les pages, d’analyser le HTML et de manipuler les données. Il existe toutefois une vraie différence entre extraire le HTML du site et utiliser l’API officielle d’eBay — j’y reviens juste après.

Pourquoi extraire eBay ? Cas d’usage concrets pour les équipes business

Si vous lisez ceci, vous avez probablement déjà une raison. Cela dit, il vaut la peine d’ancrer le sujet dans une valeur métier concrète, car le ROI des données eBay est vraiment impressionnant. Bain a constaté qu’une sur des milliers d’entreprises. McKinsey attribue à la tarification dynamique dans le retail.

Les cas d’usage que je vois le plus souvent :

Cas d’usageDonnées nécessairesRésultat métier
Surveillance des prix et repricingPrix des annonces actives, livraison, étatTarification compétitive, protection des marges
Analyse concurrentielleAssortiment produits, promotions, conditions de livraisonPositionnement stratégique, identification des manques d’assortiment
Études de marché et détection de tendancesVitesse de mise en vente, tendances de catégorie, signaux de demandeIdentification de nouveaux produits, prévision de la demande
Tarification revendeur / estimationPrix vendus, dates de vente, étatValeur de marché juste, décisions d’achat
Analyse de sentimentAvis, notes, politique de retourLecture de la qualité produit, satisfaction client
Génération de leadsProfils vendeurs, infos boutique, coordonnéesProspection B2B auprès de vendeurs à fort GMV

ebayscraping_stats_77c7da1611.png

Le point commun est simple : eBay possède les données, mais elles sont enfermées dans des pages web.

Le scraping permet d’en faire un avantage concurrentiel.

API officielle eBay vs scraping Python : lequel choisir ?

C’est la question à laquelle j’aimerais que davantage de tutoriels répondent franchement. eBay propose des API officielles — principalement la — et beaucoup se demandent s’il vaut mieux les utiliser ou extraire directement le site. La réponse dépend entièrement des données dont vous avez besoin.

CritèreAPI eBay Browse/FindingScraping Python
Annonces vendues/terminéesLimité — la Marketplace Insights API existe, mais l’accès est souvent refuséAccès complet via les paramètres d’URL LH_Sold=1&LH_Complete=1
Limites de requêtes5 000 appels/jour sur le niveau de baseGéré par vous-même (dépend des proxys)
Champs disponiblesPrédéfinis (titre, prix, catégorie, bases vendeur)Tout ce qui est visible sur la page (avis, spécifications complètes, variantes)
Complexité de mise en placeOAuth 2.0, inscription de l’application, clés APIpip install + code
StabilitéEndpoints stablesCasse quand le HTML change
CoûtOffre gratuite disponible, payante selon le volumeCode gratuit, mais coûts de proxy à grande échelle
Données de variantes/MSKUPartielles — souvent seulement le SKU parentComplètes (via l’analyse du JSON caché)
Profondeur de paginationPlafond dur de 10 000 élémentsThéoriquement illimité

Petite précision : l’ancienne Finding API (qui incluait findCompletedItems) a été . Si vous utilisez ebaysdk-python ou une bibliothèque qui s’appuie sur le module Finding, elle est actuellement cassée en production.

Ma recommandation : utilisez la Browse API pour des requêtes de catalogue stables, à volume modéré, sur les annonces actives. Utilisez le scraping Python lorsque vous avez besoin des prix vendus, des avis, des variantes ou de tout champ non exposé par l’API. Beaucoup d’équipes combinent les deux.

Outils et bibliothèques nécessaires pour extraire eBay avec Python

Avant d’écrire du code, voici la boîte à outils. Vous n’avez pas besoin d’un navigateur headless pour la plupart des pages eBay — les données sont intégrées dans le HTML rendu côté serveur.

BibliothèqueRôle
requests ou httpxClient HTTP pour télécharger les pages eBay
curl_cffiClient HTTP avec empreinte TLS de vrai navigateur (essentiel pour contourner Akamai)
beautifulsoup4Analyseur HTML pour extraire via sélecteurs CSS
lxmlMoteur d’analyse rapide pour BeautifulSoup
jmespathLangage de requête pour analyser des blocs JSON imbriqués
pandasManipulation de données et export CSV/Excel
gspreadIntégration Google Sheets

Installez tout en une seule commande :

1pip install requests httpx curl_cffi beautifulsoup4 lxml jmespath pandas gspread

Utilisez Python 3.11+ — pandas 3.0 exige au moins Python 3.10, et Python 3.11 apporte un gain de vitesse de 10 à 60 % sur les tâches liées aux I/O.

Une bibliothèque mérite une mention spéciale : curl_cffi est probablement la mise à niveau la plus importante pour un scraper eBay en 2026. eBay utilise , et le principal vecteur de détection d’Akamai est l’empreinte TLS. Un simple requests envoie une empreinte JA3 typique de Python, immédiatement repérée. curl_cffi imite la négociation TLS d’un vrai navigateur Chrome, ce qui permet de gérer environ 90 % des cibles protégées par Akamai sans navigateur headless.

Tutoriel pas à pas : comment extraire les résultats de recherche eBay avec Python

C’est le cœur du tutoriel. Nous allons extraire les pages de résultats de recherche eBay pour les annonces produits.

  • Niveau : Débutant à intermédiaire
  • Temps requis : environ 30 minutes pour une première extraction fonctionnelle
  • Ce qu’il vous faut : Python 3.11+, les bibliothèques ci-dessus, un terminal et une URL de recherche eBay cible

Étape 1 : préparer votre projet Python

Créez un dossier de projet et installez les dépendances :

1mkdir ebay-scraper && cd ebay-scraper
2python -m venv venv
3source venv/bin/activate  # Windows: venv\Scripts\activate
4pip install requests curl_cffi beautifulsoup4 lxml pandas

Créez un fichier appelé scrape_ebay.py. C’est votre espace de travail.

Étape 2 : construire l’URL de recherche eBay

La structure de l’URL de recherche eBay est simple. Le paramètre clé est _nkw (mot-clé) :

1import urllib.parse
2keyword = "airpods pro"
3base_url = "https://www.ebay.com/sch/i.html"
4params = {
5    "_nkw": keyword,
6    "_ipg": "120",    # nombre d’éléments par page : 60, 120 ou 240 (240 peut déclencher des alertes bot)
7    "_pgn": "1",      # numéro de page
8}
9url = f"{base_url}?{urllib.parse.urlencode(params)}"
10print(url)
11# https://www.ebay.com/sch/i.html?_nkw=airpods+pro&_ipg=120&_pgn=1

Autres paramètres utiles :

  • LH_BIN=1 — uniquement les annonces Acheter maintenant
  • _sacat=175673 — catégorie spécifique
  • _sop=12 — tri par meilleure correspondance (10 = prix + livraison la plus basse, 13 = plus récemment publié)
  • LH_Complete=1&LH_Sold=1 — annonces vendues/terminées (couvertes dans une section dédiée plus bas)

Étape 3 : envoyer une requête et gérer la réponse

C’est ici que curl_cffi montre toute sa valeur. Un simple requests.get() renvoie souvent une erreur 403 d’Akamai. Avec curl_cffi, on se fait passer pour un vrai navigateur Chrome :

1from curl_cffi import requests as cffi_requests
2import random, time
3USER_AGENTS = [
4    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36",
5    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36",
6    "Mozilla/5.0 (X11; Linux x86_64; rv:124.0) Gecko/20100101 Firefox/124.0",
7]
8HEADERS = {
9    "User-Agent": random.choice(USER_AGENTS),
10    "Accept-Language": "en-US,en;q=0.9",
11    "Accept-Encoding": "gzip, deflate, br",
12}
13def fetch_page(url, max_retries=5):
14    delay = 2
15    for attempt in range(max_retries):
16        try:
17            r = cffi_requests.get(url, impersonate="chrome124", headers=HEADERS, timeout=30)
18            if r.status_code == 200:
19                return r.text
20            if r.status_code in (403, 429, 503):
21                retry_after = r.headers.get("Retry-After")
22                sleep_for = float(retry_after) if retry_after else delay + random.uniform(0, 1)
23                print(f"  Statut {r.status_code}, nouvelle tentative dans {sleep_for:.1f}s...")
24                time.sleep(sleep_for)
25                delay *= 2
26                continue
27            r.raise_for_status()
28        except Exception as e:
29            print(f"  Erreur de requête : {e}, nouvelle tentative...")
30            time.sleep(delay)
31            delay *= 2
32    raise RuntimeError(f"Échec après {max_retries} tentatives : {url}")

Le backoff exponentiel avec jitter est important : des intervalles de sommeil fixes constituent eux aussi une empreinte bot.

Étape 4 : extraire les annonces produit depuis la page de recherche

eBay est actuellement en transition entre deux mises en page de résultats de recherche. Un scraper robuste doit gérer les deux :

ChampAncienne mise en pageNouvelle mise en page
Conteneur de carteli.s-itemli.s-card ou div.su-card-container
Titre.s-item__title.s-card__title
URLa.s-item__link[href]a.su-link[href]
Prixspan.s-item__price.s-card__price

Le code d’analyse qui prend en charge les deux mises en page :

1from bs4 import BeautifulSoup
2def parse_search_results(html):
3    soup = BeautifulSoup(html, "lxml")
4    cards = soup.select("li.s-item, li.s-card, div.su-card-container")
5    results = []
6    for card in cards:
7        # Titre — essayer les deux mises en page
8        title_el = card.select_one(".s-item__title, .s-card__title")
9        title = title_el.get_text(strip=True) if title_el else None
10        # Ignorer la fausse carte de remplacement “Shop on eBay”
11        if not title or "Shop on eBay" in title:
12            continue
13        # Prix
14        price_el = card.select_one("span.s-item__price, .s-card__price")
15        price = price_el.get_text(strip=True) if price_el else None
16        # URL
17        link_el = card.select_one("a.s-item__link[href], a.su-link[href]")
18        url = link_el["href"].split("?")[0] if link_el else None
19        # Image
20        img_el = card.select_one("img.s-item__image-img, .s-card__image img")
21        image = None
22        if img_el:
23            image = img_el.get("src") or img_el.get("data-src")
24        # Livraison
25        ship_el = card.select_one("span.s-item__shipping, span.s-item__logisticsCost, .s-card__attribute-row")
26        shipping = ship_el.get_text(strip=True) if ship_el else None
27        results.append({
28            "title": title,
29            "price": price,
30            "url": url,
31            "image": image,
32            "shipping": shipping,
33        })
34    return results

Le piège de la première carte fantôme est un classique. Sur beaucoup de pages de recherche eBay, le premier li.s-item est un espace réservé caché, avec le titre “Shop on eBay” et aucun vrai prix. Filtrez-le systématiquement.

Étape 5 : gérer la pagination pour extraire plusieurs pages

eBay pagine via le paramètre _pgn. Le lien de la page suivante utilise a.pagination__next :

1import urllib.parse
2def scrape_ebay_search(keyword, max_pages=5):
3    all_results = []
4    for page_num in range(1, max_pages + 1):
5        params = {"_nkw": keyword, "_ipg": "120", "_pgn": str(page_num)}
6        url = f"https://www.ebay.com/sch/i.html?{urllib.parse.urlencode(params)}"
7        print(f"Extraction de la page {page_num} : {url}")
8        html = fetch_page(url)
9        results = parse_search_results(html)
10        if not results:
11            print(f"  Aucun résultat sur la page {page_num}, arrêt.")
12            break
13        all_results.extend(results)
14        print(f"  {len(results)} annonces trouvées (total : {len(all_results)})")
15        # Pause polie — 3 à 8 secondes avec jitter
16        time.sleep(random.uniform(3, 8))
17    return all_results

Le jitter aléatoire de 3 à 8 secondes n’est pas optionnel.

eBay et Akamai détectent les rafales continues de plus de 1 requête/seconde depuis une même IP.

Étape 6 : exporter vos données en CSV ou JSON

1import pandas as pd
2results = scrape_ebay_search("airpods pro", max_pages=3)
3df = pd.DataFrame(results)
4df.to_csv("ebay_airpods.csv", index=False)
5df.to_json("ebay_airpods.json", orient="records", indent=2)
6print(f"Export de {len(df)} annonces vers CSV et JSON.")

Vous devriez maintenant disposer d’un tableau propre des annonces eBay. Sur ma machine, l’extraction de 3 pages (360 annonces) a pris environ 45 secondes, pauses incluses.

Comment extraire les pages de détail produit eBay avec Python

Les résultats de recherche donnent un aperçu. Les pages de détail produit contiennent les éléments utiles : descriptions complètes, notes du vendeur, caractéristiques de l’article, carrousels d’images et données de variantes.

Analyser une page d’annonce individuelle

Les pages d’articles eBay se trouvent à l’URL /itm/<ITEM_ID>. La voie d’extraction la plus stable est JSON-LD — eBay intègre un bloc de schéma Product qui survit à presque tous les changements de CSS :

1import json
2def parse_item_page(html):
3    soup = BeautifulSoup(html, "lxml")
4    item = {}
5    # 1. JSON-LD — voie d’extraction la plus stable
6    for tag in soup.find_all("script", type="application/ld+json"):
7        try:
8            data = json.loads(tag.string or "")
9        except (json.JSONDecodeError, TypeError):
10            continue
11        if isinstance(data, dict) and data.get("@type") == "Product":
12            item["title"] = data.get("name")
13            item["brand"] = (data.get("brand") or {}).get("name")
14            item["images"] = data.get("image")
15            offers = data.get("offers") or {}
16            item["price"] = offers.get("price")
17            item["currency"] = offers.get("priceCurrency")
18            break
19    # 2. Fallback CSS pour les champs absents du JSON-LD
20    def first_text(selectors):
21        for sel in selectors:
22            el = soup.select_one(sel)
23            if el and el.get_text(strip=True):
24                return el.get_text(strip=True)
25        return None
26    item.setdefault("title", first_text([
27        "h1.x-item-title__mainTitle",
28        "h1.x-item-title__mainTitle .ux-textspans--BOLD",
29    ]))
30    item["condition"] = first_text([
31        ".x-item-condition-text .ux-textspans",
32    ])
33    item["seller"] = first_text([
34        ".x-sellercard-atf__info__about-seller a .ux-textspans",
35    ])
36    item["shipping"] = first_text([
37        "div.ux-labels-values--shipping .ux-textspans--BOLD",
38    ])
39    # 3. Caractéristiques de l’article
40    specifics = {}
41    for dl in soup.select(".ux-layout-section-evo__item--table-view dl.ux-labels-values"):
42        k = dl.select_one(".ux-labels-values__labels-content .ux-textspans")
43        v = dl.select_one(".ux-labels-values__values-content .ux-textspans")
44        if k and v:
45            specifics[k.get_text(strip=True).rstrip(":")] = v.get_text(strip=True)
46    item["specifics"] = specifics
47    return item

Le schéma ici — JSON-LD d’abord, sélecteurs CSS en secours — est la clé pour construire des scrapers qui ne cassent pas tous les trimestres. J’y reviens plus bas.

Extraire les variantes de produit eBay (données MSKU)

Certaines annonces eBay proposent plusieurs variantes — différentes couleurs, tailles ou capacités de stockage. Le DOM visible n’affiche qu’une fourchette de prix, par exemple “899 $ à 1 099 $”, jusqu’à ce que l’utilisateur clique sur une option. Le prix réel par variante se trouve dans un objet JavaScript caché appelé MSKU.

C’est l’un des cas où l’API eBay ne fournit qu’une partie des données (le SKU parent), ce qui rend le scraping plus pertinent.

1import re, json
2def extract_variants(html):
3    # Le caractère non gourmand est essentiel — le .+ gourmand engloutit toute la page
4    m = re.search(r'"MSKU"\s*:\s*(\{.+?\})\s*,\s*"QUANTITY"', html, re.DOTALL)
5    if not m:
6        return []
7    try:
8        msku = json.loads(m.group(1))
9    except json.JSONDecodeError:
10        return []
11    item_labels = {str(k): v["displayLabel"] for k, v in msku.get("menuItemMap", {}).items()}
12    skus = []
13    for combo_key, variation_id in msku.get("variationCombinations", {}).items():
14        option_ids = combo_key.split("_")
15        options = [item_labels.get(oid, oid) for oid in option_ids]
16        var = msku.get("variationsMap", {}).get(str(variation_id), {})
17        bin_model = var.get("binModel", {})
18        price_spans = bin_model.get("price", {}).get("textSpans", [{}])
19        price = price_spans[0].get("text") if price_spans else None
20        qty = var.get("quantity")
21        skus.append({
22            "options": options,
23            "price": price,
24            "quantity_available": qty,
25            "variation_id": variation_id,
26        })
27    return skus

C’est dans cette regex (.+?) non gourmande que la plupart des scrapers eBay se font piéger. Le .+ gourmand avale tout jusqu’au dernier "QUANTITY" de la page, ce qui produit un JSON invalide. J’ai vu ce bug dans au moins trois tutoriels “fonctionnels”.

Comment extraire les annonces eBay vendues et terminées avec Python

C’est le cas d’usage qui justifie le scraping plutôt que l’API. Les données d’articles vendus — ce qui a réellement été vendu, à quel prix et à quelle date — constituent la référence absolue pour les études de marché, la tarification des revendeurs et les estimations. La Browse API d’eBay ne fournit pas cela explicitement. La le fait techniquement, mais l’accès relève d’une “Limited Release” souvent .

Les paramètres d’URL nécessaires sont LH_Complete=1 (annonces terminées) et LH_Sold=1 (uniquement les articles effectivement vendus). Vous devez fournir les deux. Si vous ne passez que LH_Sold=1, eBay revient silencieusement aux annonces actives dans certaines catégories — c’est l’erreur la plus fréquente.

1def scrape_sold_listings(keyword, max_pages=3):
2    all_sold = []
3    for page_num in range(1, max_pages + 1):
4        params = {
5            "_nkw": keyword,
6            "_ipg": "120",
7            "_pgn": str(page_num),
8            "LH_Complete": "1",
9            "LH_Sold": "1",
10        }
11        url = f"https://www.ebay.com/sch/i.html?{urllib.parse.urlencode(params)}"
12        print(f"Extraction des annonces vendues, page {page_num}...")
13        html = fetch_page(url)
14        soup = BeautifulSoup(html, "lxml")
15        cards = soup.select("li.s-item")
16        for card in cards:
17            title_el = card.select_one(".s-item__title")
18            title = title_el.get_text(strip=True) if title_el else None
19            if not title or "Shop on eBay" in title:
20                continue
21            # N’inclure que les articles effectivement vendus (prix POSITIVE vert)
22            sold_tag = card.select_one(
23                ".s-item__title--tag .POSITIVE, .s-item__caption--signal.POSITIVE"
24            )
25            if sold_tag is None:
26                continue  # Annonce terminée non vendue — à ignorer
27            price_el = card.select_one("span.s-item__price")
28            price = price_el.get_text(strip=True) if price_el else None
29            # Extraire la date de vente
30            sold_date = None
31            import re, datetime as dt
32            card_text = card.get_text()
33            m = re.search(r"Sold\s+([A-Z][a-z]{2}\s+\d{1,2},\s*\d{4})", card_text)
34            if m:
35                sold_date = dt.datetime.strptime(m.group(1), "%b %d, %Y").strftime("%Y-%m-%d")
36            link_el = card.select_one("a.s-item__link[href]")
37            url = link_el["href"].split("?")[0] if link_el else None
38            all_sold.append({
39                "title": title,
40                "sold_price": price,
41                "sold_date": sold_date,
42                "url": url,
43            })
44        if not cards:
45            break
46        time.sleep(random.uniform(3, 8))
47    return all_sold

La différence clé dans le HTML : les articles vendus affichent le prix en vert (dans un conteneur .POSITIVE), alors que les annonces terminées non vendues affichent le prix en rouge barré. Filtrez toujours sur cette classe .POSITIVE.

Pourquoi les scrapers eBay cassent-ils ? Et comment construire des scrapers robustes

Si votre scraper eBay ne fonctionne plus, vous êtes loin d’être seul. C’est le problème numéro un dans tous les fils de discussion sur le scraping eBay que j’ai lus. La question n’est pas de savoir si votre scraper cassera, mais quand.

Pourquoi cela arrive :

  • eBay utilise un rendu basé sur React avec des noms de classes générés dynamiquement qui changent à chaque déploiement
  • Les tests A/B servent des structures DOM différentes selon les utilisateurs (la double mise en page s-item / s-card en est un exemple vivant)
  • Les refontes périodiques modifient l’imbrication HTML même quand les données restent identiques
  • Les anciens sélecteurs comme #itemTitle et #prcIsum ont été supprimés il y a des années, mais ils apparaissent encore dans des tutoriels

Comme le dit : « Le vrai défi du scraping eBay consiste à gérer les changements de sélecteurs CSS. eBay met régulièrement à jour son frontend, ce qui casse les scrapers dépendants de noms de classes spécifiques. »

ebayscraping_section_50be5cc410.png

Stratégies de défense pour des scrapers eBay durables

Quatre stratégies qui survivent aux remaniements trimestriels d’eBay :

1. Priorisez le JSON-LD plutôt que les sélecteurs CSS. eBay intègre des données structurées Product sur chaque page d’article. La couche de données change beaucoup moins que la couche de présentation — les designers refondent les classes CSS tous les trimestres, mais les noms de champs côté backend comme price, name et seller sont reliés à des API internes et sont rarement renommés.

2. Utilisez des sélecteurs de secours en cascade. Ne dépendez jamais d’un seul sélecteur CSS. Proposez toujours des alternatives :

1def first_text(soup, selectors):
2    for sel in selectors:
3        el = soup.select_one(sel)
4        if el and el.get_text(strip=True):
5            return el.get_text(strip=True)
6    return None
7title = first_text(soup, [
8    "h1.x-item-title__mainTitle",
9    "h1.x-item-title__mainTitle .ux-textspans--BOLD",
10    "[data-testid='x-item-title'] h1",
11])

3. Analysez les blocs JSON cachés. L’objet de variantes MSKU et les données JavaScript inline résistent mieux aux changements CSS car ils sont générés côté serveur. Extraire ces données via regex dans des balises <script> demande plus d’effort au départ, mais réduit fortement la maintenance.

4. Journalisez les échecs de sélecteurs. Ajoutez une supervision pour savoir quand un sélecteur cesse de fonctionner, et pas seulement que vos données sont vides :

1if title is None:
2    print(f"AVERTISSEMENT : échec du sélecteur de titre pour {url}")

5. Utilisez curl_cffi avec impersonation de navigateur. Cela gère l’empreinte TLS d’Akamai sans navigateur headless.

L’alternative alimentée par l’IA : plus de maintenance des sélecteurs

Si vous en avez assez de corriger les sélecteurs tous les quelques mois, il existe une approche fondamentalement différente. Des outils comme utilisent l’IA pour lire la page à chaque exécution et déduire la logique d’extraction à la volée. Une étude de l’Université McGill a comparé des scrapers IA et des scrapers basés sur des sélecteurs sur 3 000 pages et a constaté que , avec des benchmarks sectoriels indiquant .

ApprocheCasse quand eBay modifie le HTML ?Effort de maintenance
Sélecteurs CSS codés en durOui, tous les trimestresÉlevé — corrections continues
Extraction JSON / JSON-LD cachéeRarementFaible
Scraping basé sur l’IA (Thunderbit)Non — l’IA redéduit les sélecteurs à chaque exécutionAucun

Je détaillerai le flux Thunderbit plus loin. Pour l’instant, retenez ceci : si vous construisez un scraper que vous comptez faire tourner pendant des mois, misez sur une extraction d’abord en JSON avec des sélecteurs de secours. Si vous ne voulez pas maintenir de sélecteurs du tout, l’approche IA mérite vraiment qu’on s’y intéresse.

Automatiser des extractions eBay récurrentes pour le suivi des prix

Une extraction ponctuelle est utile. Mais la surveillance des prix, le suivi des stocks et l’analyse concurrentielle exigent une collecte récurrente des données. Tous les articles comparatifs que j’ai lus mentionnent le suivi des prix comme cas d’usage, mais presque aucun n’explique comment l’automatiser réellement.

Option 1 : Cron jobs (Linux/macOS) ou Planificateur de tâches (Windows)

L’approche la plus simple. Enveloppez votre script Python dans un cron job. Utilisez toujours le chemin absolu vers le Python de votre environnement virtuel — cron s’exécute dans un environnement minimal :

1crontab -e
2# Tous les jours à 08:15
315 8 * * * /Users/me/ebay/venv/bin/python /Users/me/ebay/scrape_ebay.py >> /Users/me/ebay/scrape.log 2>&1

Sous Windows, utilisez PowerShell :

1$A = New-ScheduledTaskAction -Execute "C:\Users\me\ebay\venv\Scripts\python.exe" -Argument "C:\Users\me\ebay\scrape_ebay.py"
2$T = New-ScheduledTaskTrigger -Daily -At 8:15am
3Register-ScheduledTask -TaskName "eBayScraper" -Action $A -Trigger $T

Cela nécessite une machine toujours allumée, et vous gérez vous-même les proxys et les mécanismes anti-bot.

Option 2 : fonctions cloud (serverless)

AWS Lambda ou Google Cloud Functions permettent d’exécuter des scrapers sans serveur dédié. La mise en place est plus lourde — il faut empaqueter les dépendances, gérer les timeouts (Lambda est limité à 15 minutes) et toujours gérer les proxys. Mais il n’y a pas de maintenance serveur.

Option 3 : planification sans code avec Thunderbit

La fonctionnalité vous permet de décrire l’intervalle en langage naturel (par exemple, “tous les jours à 8h”), d’ajouter des URL eBay, puis de cliquer sur Planifier. L’exécution se fait dans le cloud avec une gestion anti-bot intégrée.

ApprocheEffort de mise en placeBesoin d’un serveur ?Gère l’anti-bot ?
Cron + script PythonMoyenOui (machine toujours allumée)Vous gérez les proxys
Fonction cloud (Lambda)ÉlevéNon (serverless)Vous gérez les proxys
Scheduled Scraper ThunderbitFaible (description en langage naturel)Non (cloud)Intégré

Pour stocker les données d’extraction récurrentes, une base SQLite locale est la bonne solution pour l’historique des prix. Utilisez ON CONFLICT ... DO UPDATE (et non INSERT OR REPLACE, qui ) :

1CREATE TABLE IF NOT EXISTS listings (
2    item_id       TEXT PRIMARY KEY,
3    title         TEXT NOT NULL,
4    price         REAL,
5    last_price    REAL,
6    first_seen_at TEXT DEFAULT (datetime('now')),
7    last_seen_at   TEXT DEFAULT (datetime('now'))
8);
9CREATE TABLE IF NOT EXISTS price_history (
10    item_id     TEXT NOT NULL,
11    observed_at TEXT NOT NULL DEFAULT (datetime('now')),
12    price       REAL NOT NULL,
13    PRIMARY KEY (item_id, observed_at)
14);

Vous ne voulez pas coder ? Comment extraire eBay en 2 minutes avec Thunderbit

J’ai passé 2 000 mots sur du code Python. Maintenant, je veux être honnête sur les cas où vous n’en avez pas besoin.

Si vous êtes un utilisateur métier qui fait une étude de marché ponctuelle, un revendeur qui compare des ventes, ou une équipe e-commerce qui a besoin de données aujourd’hui sans sprint de développement, Python est excessif. La configuration, la maintenance des sélecteurs, la gestion des proxys — tout cela est beaucoup trop lourd pour “j’ai juste besoin de ces 200 annonces dans un tableur”.

Comment Thunderbit extrait eBay (étape par étape)

  1. Installez l’ — sans carte bancaire.
  2. Ouvrez une page de résultats de recherche eBay ou une page produit dans Chrome.
  3. Cliquez sur “AI Suggest Fields” dans la barre latérale Thunderbit. L’IA lit la page et propose des colonnes : Titre, Prix, État, Livraison, Vendeur, Note.
  4. Cliquez sur “Scrape.” L’extension parcourt la pagination et remplit le tableau de données. Pour eBay en particulier, Thunderbit propose des qui fonctionnent en un clic.
  5. Exportez vers Google Sheets, Airtable, Notion, CSV, JSON ou Excel — gratuitement.

Le tout prend moins de 2 minutes.

Je l’ai chronométré.

Enrichissement des sous-pages : récupérer les données de la fiche détaillée sans code supplémentaire

Après l’extraction d’une page de résultats, Thunderbit peut ouvrir la page détaillée de chaque annonce et ajouter des champs supplémentaires — spécifications complètes, infos vendeur, description, toutes les images. Cela remplace les plus de 20 lignes de code Python pour le scraping de sous-pages que nous avons écrites plus haut par un simple clic.

Quand Python reste le bon choix

Python prend l’avantage lorsque vous avez besoin de :

  • Scraping à grande échelle (dizaines de milliers de pages par exécution)
  • Logique d’analyse ou de transformation très personnalisée
  • Intégration à des pipelines de données existants (Airflow, dbt, Kafka)
  • Contrôle fin du TLS/de la session pour des travaux anti-bot avancés
  • Économie unitaire — à des millions de lignes, une stack maintenue coûte souvent moins cher qu’un SaaS à crédits

Pour la plupart des projets ponctuels ou de taille moyenne, Thunderbit est plus rapide et plus simple. Pour des pipelines de production à grande échelle, Python offre un contrôle total.

Conseils pour éviter le blocage lorsque vous extrayez eBay avec Python

eBay et Akamai, c’est du sérieux. Ce qui fonctionne réellement en pratique :

  • Utilisez curl_cffi avec impersonate="chrome124" — c’est l’amélioration la plus importante par rapport à un simple requests
  • Faites tourner les chaînes User-Agent à partir d’une liste de navigateurs récents (Chrome 143, Firefox 124, Safari 26)
  • Ajoutez des délais aléatoires de — des intervalles fixes sont une empreinte
  • Utilisez des proxys résidentiels ou rotatifs pour dépasser quelques dizaines de pages. Les IP de datacenters (AWS, GCP, DigitalOcean) sont rapidement repérées par Akamai.
  • Respectez robots.txt — la plupart des URL de navigation filtrées sont explicitement interdites ; les pages de détail d’articles (/itm/<id>) ne le sont pas
  • Gérez les CAPTCHA avec souplesse — détectez-les et réessayez avec une autre IP, ou utilisez un service de résolution de CAPTCHA
  • Ne surchargez pas le serveur. Le précédent indique que le “trespass to chattels” s’applique lorsque le scraping dégrade réellement les serveurs. Rester à 1 requête/seconde par IP vous maintient largement sous ce seuil.

Pour un usage commercial à fort volume, envisagez la Browse API pour les annonces actives et un scraping ciblé uniquement pour les comparables vendus et les données non exposées par l’API. Cette approche hybride est plus propre, à la fois techniquement et juridiquement.

Est-il légal d’extraire eBay avec Python ?

Je ne suis pas avocat, et cet article ne constitue pas un avis juridique. Je vais donc rester bref.

Le paysage juridique a évolué en faveur de l’extraction de données publiques. Les précédents clés :

  • (9e circuit, 2022) : l’extraction de données accessibles publiquement ne viole pas le CFAA
  • Van Buren v. United States (Cour suprême des États-Unis, 2021) : interprétation plus stricte de la notion “exceeds authorized access” du CFAA
  • (N.D. Cal., 2024) : le scraping sans connexion ne viole pas les CGU de la plateforme, car le scraper n’est pas un “utilisateur”

Cela dit, la mise à jour interdit explicitement les “agents buy-for-me, les bots pilotés par des LLM, ou tout flux de bout en bout qui tente de passer des commandes sans revue humaine”. La ligne est claire : l’extraction en lecture seule de pages publiques est solidement défendable ; l’automatisation du checkout ne l’est pas.

Bonnes pratiques : n’extrayez que les données visibles publiquement. Ne créez pas de faux comptes et ne contournez pas les murs de connexion. Ne revendiez pas en masse des images d’annonces protégées par le droit d’auteur. Et consultez un juriste pour les projets à l’échelle commerciale.

Conclusion et points clés à retenir

Python reste la méthode la plus flexible pour extraire eBay, mais il exige une maintenance continue à mesure que le HTML du site évolue. Le cadre de décision :

  • Utilisez la Browse API eBay pour des requêtes stables, de volume modéré, sur les annonces actives
  • Utilisez le scraping Python pour les annonces vendues, les avis, les variantes et tout champ non exposé par l’API
  • Utilisez si vous voulez les données eBay sans écrire ni maintenir de code

Le code de ce guide privilégie la robustesse : extraction JSON-LD en premier, sélecteurs CSS de secours ensuite, analyse du JSON caché pour les variantes. Cette approche en couches signifie que votre scraper ne mourra pas à la prochaine refonte du frontend d’eBay.

Si vous voulez essayer l’option sans code, vous permet de la tester dès maintenant sur des pages eBay. Et si vous voulez voir comment fonctionne le , il est à un clic.

Pour aller plus loin sur les outils de scraping web, consultez nos guides sur les , et . Vous pouvez aussi regarder des tutoriels sur la .

Essayez Thunderbit pour extraire eBay

FAQ

1. Puis-je extraire eBay gratuitement avec Python ?

Oui. Toutes les bibliothèques (Requests, BeautifulSoup, curl_cffi, pandas) sont gratuites et open source. Les coûts apparaissent à grande échelle — les proxys résidentiels pour du scraping intensif coûtent généralement entre 50 et 500 $/mois selon la bande passante. Pour de petits projets (quelques centaines de pages), vous pouvez extraire depuis votre IP domestique avec une limitation de débit prudente.

2. Comment extraire les articles vendus et les annonces terminées eBay avec Python ?

Ajoutez LH_Complete=1&LH_Sold=1 aux paramètres de l’URL de recherche. Vous devez passer les deux — LH_Sold=1 seul revient silencieusement aux annonces actives dans certaines catégories. Filtrez les résultats en vérifiant la classe CSS .POSITIVE sur l’élément de prix, ce qui indique une vente réelle plutôt qu’une annonce expirée invendue.

3. eBay bloque-t-il le scraping web ?

eBay utilise Akamai Bot Manager, qui détecte les scrapers principalement via l’empreinte TLS et l’analyse comportementale. De simples appels requests renvoient souvent des réponses 403. L’utilisation de curl_cffi avec impersonation du navigateur, la rotation des User-Agents et l’ajout de délais aléatoires de 3 à 8 secondes entre les requêtes permettent de contourner la plupart des blocages. Les proxys résidentiels aident à grande échelle.

4. Dois-je utiliser l’API eBay ou le web scraping ?

Utilisez la Browse API pour les requêtes stables et de volume modéré sur les annonces actives (jusqu’à 5 000 appels/jour). Utilisez le scraping quand vous avez besoin de l’historique des prix vendus, des données complètes de variantes/MSKU, des avis ou de tout champ non exposé par l’API. La Marketplace Insights API fournit théoriquement les données de vente, mais l’accès est restreint et .

5. Quelle est la façon la plus simple d’extraire eBay sans coder ?

L’ utilise l’IA pour lire les pages eBay, suggérer les colonnes de données et extraire les annonces en un clic. Elle gère la pagination, l’enrichissement des sous-pages et l’export vers Google Sheets, Excel, Airtable ou Notion. Les préconfigurés rendent cela encore plus rapide pour les cas d’usage courants.

En savoir plus

Ke
Ke
CTO @ Thunderbit. Ke is the person everyone pings when data gets messy. He's spent his career turning tedious, repetitive work into quiet little automations that just run. If you've ever wished a spreadsheet could fill itself in, Ke has probably already built the thing that does it.
Table des matières

Essaie Thunderbit

Extrayez des leads et d’autres données en seulement 2 clics. Propulsé par l’IA.

Obtenir Thunderbit C’est gratuit
Extraire des données grâce à l’IA
Transfère facilement les données vers Google Sheets, Airtable ou Notion
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week