Scraper Etsy pour la recherche de niche POD : guide pratique 2025

Apprenez à scraper Etsy de manière fiable pour la recherche de niche print-on-demand : structure du site, anti-bot Cloudflare, rotation de proxies résidentiels et scripts Python prêts à l'emploi.

Scraper Etsy pour la recherche de niche POD : guide pratique 2025

Scrape Etsy : API interne vs HTML — quelles options pour la recherche de niche ?

Si vous cherchez à scraper Etsy pour trouver votre prochaine niche print-on-demand, vous avez deux voies : l'API interne non documentée d'Etsy ou le parsing HTML classique. Chaque approche a des compromis très concrets.

API interne (endpoint /api/v3/ajax/member/search) — Etsy expose des endpoints JSON utilisés par son front-end React. Ils renvoient des données structurées (titres, prix, images, shop_id) sans avoir à parser le DOM. Le problème : ces endpoints sont protégés par des tokens CSRF et des headers personnalisés qui changent régulièrement, et le rate limiting y est plus agressif (~60 req/min avant blocage temporaire).

HTML scraping — Plus robuste sur le long terme. Le HTML des pages de recherche contient tout ce dont vous avez besoin via des selecteurs CSS stables. Le rate limiting est aussi présent mais légèrement plus permissif (~100-120 req/min avant déclenchement Cloudflare). C'est l'approche que nous recommandons pour la recherche de niche Etsy.

Dans ce guide, nous combinons les deux : HTML pour les résultats de recherche, API interne pour les détails de listing quand c'est disponible. Et nous utilisons des proxies résidentiels pour rester sous le radar.

Structure d'Etsy : comprendre le site avant de le scraper

Pages de recherche

L'URL de recherche d'Etsy suit ce pattern :

https://www.etsy.com/search?q=funny+mug&ref=search_bar&order=highest_reviews

Paramètres utiles :

  • q — le terme de recherche
  • orderhighest_reviews, lowest_price, highest_price, newest
  • page — pagination (1 à ~250)
  • location_query — filtre géographique

Chaque page affiche jusqu'à 48 listing cards. Les données clés sont dans des éléments <div data-search-results> et les cards individuelles suivent le sélecteur .v2-listing-card.

Pages de listing (détail produit)

URL : https://www.etsy.com/listing/{listing_id}/{slug}

Données disponibles : titre complet, description, prix, variantes, nombre de favoris, avis, badge ventes du shop. Le JSON embarqué dans <script type="application/ld+json"> contient la plupart des métadonnées.

Pages de shop

URL : https://www.etsy.com/shop/{shop_name}

On y trouve : nombre total de listings, badge "X sales" (ventes approximatives), avis, localisation, date de création. Le sélecteur CSS .shop-info et le JSON-LD sont vos amis.

Arbre de catégories

Etsy organise ses catégories hiérarchiquement : /c/clothing/women, /c/home-and-living/home-decor, etc. Scraper l'arbre complet permet de découvrir des niches avec peu de concurrence. L'endpoint https://www.etsy.com/api/v3/ajax/member/categories retourne parfois l'arbre en JSON, mais il est plus fiable de parser la page /categories.

Anti-bot Etsy : Cloudflare et rate limits internes

Etsy utilise Cloudflare avec le mode "Under Attack" activé dynamiquement. Voici ce que nous avons observé en production :

SeuilComportementDurée du blocage
~100-120 req/min (même IP)Challenge JavaScript Cloudflare5-15 min
~300-500 req/minCaptcha hCaptcha15-60 min
Pattern de scraping évidentBan IP (403 permanent)24h+ ou permanent

Pourquoi les proxies résidentiels sont indispensables : les IPs datacenter sont presque immédiatement flaguées par Cloudflare. Les IPs résidentielles, en revanche, se fondent dans le trafic normal d'Etsy. C'est là qu'un proxy résidentiel de qualité fait toute la différence.

Conseils pratiques :

  • Rottez l'IP toutes les 30-50 requêtes avec des sessions résidentielles
  • Ajoutez un délai aléatoire de 2-5 secondes entre les requêtes
  • Faites tourner les User-Agents (Chrome, Firefox, Edge — versions récentes)
  • Acceptez les headers accept-language: en-US,en;q=0.9 et les cookies Cloudflare

Patterns de scraping pour la découverte de niche

La recherche de niche sur Etsy repose sur trois métriques clés : les termes de recherche tendance, le nombre de vendeurs par niche et le prix moyen.

Termes de recherche tendance

Etsy expose ses suggestions de recherche via l'endpoint d'autocomplétion :

https://www.etsy.com/api/v3/ajax/member/search-suggestions?query=funny

Réponse tronquée :

{
  "results": [
    {"query": "funny mug", "type": "search_suggestion"},
    {"query": "funny t shirt women", "type": "search_suggestion"},
    {"query": "funny birthday card", "type": "search_suggestion"},
    {"query": "funny cat shirt", "type": "search_suggestion"}
  ]
}

En itérant sur des racines de mots-clés, vous pouvez construire une carte complète des niches tendance. Croisez ces données avec le nombre de résultats pour chaque terme pour estimer la concurrence.

Nombre de vendeurs et prix moyen par niche

Pour chaque terme de recherche, scrapez la première page de résultats et extrayez :

  • shop_name unique — pour compter le nombre de vendeurs distincts
  • price — pour calculer le prix moyen et médian
  • reviews_count — indicateur de volume de ventes

Un ratio suggestions / vendeurs_uniques élevé signale une niche sous-desservie — l'eldorado pour le POD.

Signaux de validation

  • Plus de 5 vendeurs avec des centaines d'avis = demande validée
  • Prix médian > 20$ pour un mug = marge suffisante pour POD
  • Moins de 50 résultats pour un terme avec suggestions = niche émergente

Script Python : scraper les résultats de recherche Etsy avec rotation de proxies

Voici un script complet qui recherche un terme, parse les listing cards, puis visite chaque page de détail pour extraire des métriques supplémentaires.

import requests
from bs4 import BeautifulSoup
import time
import random
import json

# Configuration ProxyHat — proxies résidentiels avec rotation par pays
PROXY_URL = "http://user-country-US:PASSWORD@gate.proxyhat.com:8080"
PROXIES = {"http": PROXY_URL, "https": PROXY_URL}

HEADERS = {
    "User-Agent": (
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
        "AppleWebKit/537.36 (KHTML, like Gecko) "
        "Chrome/125.0.0.0 Safari/537.36"
    ),
    "Accept-Language": "en-US,en;q=0.9",
    "Accept": "text/html,application/xhtml+xml",
}

def fetch_search_results(keyword, page=1):
    """Scrape une page de résultats de recherche Etsy."""
    url = f"https://www.etsy.com/search?q={keyword.replace(' ', '+')}&page={page}"
    resp = requests.get(url, headers=HEADERS, proxies=PROXIES, timeout=30)
    resp.raise_for_status()
    return resp.text

def parse_listing_cards(html):
    """Extrait les données des listing cards depuis le HTML."""
    soup = BeautifulSoup(html, "html.parser")
    cards = soup.select(".v2-listing-card")
    listings = []
    for card in cards:
        link = card.select_one("a.listing-link")
        title_el = card.select_one(".v2-listing-card__info .title")
        price_el = card.select_one(".currency-value")
        if not link:
            continue
        href = link.get("href", "")
        listing_id = href.split("/listing/")[-1].split("/")[0] if "/listing/" in href else ""
        listings.append({
            "listing_id": listing_id,
            "title": title_el.get_text(strip=True) if title_el else "",
            "price": price_el.get_text(strip=True) if price_el else "",
            "url": f"https://www.etsy.com{href}" if href.startswith("/") else href,
        })
    return listings

def fetch_listing_detail(listing_url, session_id):
    """Scrape les détails d'un listing avec une session proxy sticky."""
    # Session sticky pour garder la même IP pendant la session
    proxy = f"http://user-session-{session_id}-country-US:PASSWORD@gate.proxyhat.com:8080"
    proxies = {"http": proxy, "https": proxy}
    resp = requests.get(listing_url, headers=HEADERS, proxies=proxies, timeout=30)
    resp.raise_for_status()
    soup = BeautifulSoup(resp.text, "html.parser")

    # Extraire le JSON-LD pour les métadonnées structurées
    ld_json = soup.find("script", type="application/ld+json")
    data = json.loads(ld_json.string) if ld_json else {}

    # Badge ventes du shop
    sales_badge = soup.select_one(".shop-sales-badge")
    sales_text = sales_badge.get_text(strip=True) if sales_badge else ""

    # Nombre de favoris
    fav_el = soup.select_one("[data-favorite-count]")
    fav_count = fav_el.get("data-favorite-count", "0") if fav_el else "0"

    return {
        "name": data.get("name", ""),
        "price": data.get("offers", {}).get("price", ""),
        "description": data.get("description", "")[:200],
        "sales_badge": sales_text,
        "favorites": fav_count,
    }

# --- Exécution ---
keyword = "funny cat mug"
print(f"Recherche : {keyword}")
html = fetch_search_results(keyword, page=1)
listings = parse_listing_cards(html)
print(f"{len(listings)} listings trouvés")

for i, listing in enumerate(listings[:5]):
    time.sleep(random.uniform(2, 5))  # Délai aléatoire anti-détection
    detail = fetch_listing_detail(listing["url"], session_id=f"etsy{i}")
    print(json.dumps({**listing, **detail}, indent=2, ensure_ascii=False))

Points clés de ce script :

  • Rotation d'IP via user-country-US pour les recherches, user-session-{id} pour les sessions sticky sur les pages de détail
  • Délai aléatoire de 2-5 secondes entre chaque requête
  • JSON-LD comme source primaire de données structurées — plus fiable que le parsing CSS
  • Fallback CSS pour les données non présentes dans le JSON-LD (badge ventes, favoris)

Analyser les shops Etsy : listings, ventes et avis

Les pages de shop Etsy sont une mine d'or pour la veille concurrentielle. Voici un script dédié :

import requests
from bs4 import BeautifulSoup
import re
import json

PROXY_URL = "http://user-country-US:PASSWORD@gate.proxyhat.com:8080"
PROXIES = {"http": PROXY_URL, "https": PROXY_URL}

HEADERS = {
    "User-Agent": (
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
        "AppleWebKit/537.36 (KHTML, like Gecko) "
        "Chrome/125.0.0.0 Safari/537.36"
    ),
    "Accept-Language": "en-US,en;q=0.9",
}

def scrape_shop(shop_name):
    """Scrape les métriques clés d'un shop Etsy."""
    url = f"https://www.etsy.com/shop/{shop_name}"
    resp = requests.get(url, headers=HEADERS, proxies=PROXIES, timeout=30)
    resp.raise_for_status()
    soup = BeautifulSoup(resp.text, "html.parser")

    # Nombre de listings
    listing_count_el = soup.select_one(".shop-info-listing-count")
    listing_count = listing_count_el.get_text(strip=True) if listing_count_el else "N/A"

    # Badge ventes — Etsy affiche "X Sales" ou "X,XXX Sales"
    sales_el = soup.select_one(".shop-sales")
    sales_raw = sales_el.get_text(strip=True) if sales_el else "0"
    sales_number = int(re.sub(r"[^0-9]", "", sales_raw) or "0")

    # Note moyenne et nombre d'avis
    review_el = soup.select_one(".shop-review-rating")
    rating = review_el.get_text(strip=True) if review_el else "N/A"
    review_count_el = soup.select_one(".shop-review-count")
    review_count = review_count_el.get_text(strip=True) if review_count_el else "0"

    # Localisation
    location_el = soup.select_one(".shop-location")
    location = location_el.get_text(strip=True) if location_el else "N/A"

    return {
        "shop_name": shop_name,
        "listing_count": listing_count,
        "sales_approx": sales_number,
        "rating": rating,
        "review_count": review_count,
        "location": location,
    }

# Exemple d'usage
result = scrape_shop("ExampleShopName")
print(json.dumps(result, indent=2))

Métriques à calculer pour chaque shop

  • Ventes par listing = sales_approx / listing_count — un ratio élevé indique des produits performants
  • Densité d'avis = review_count / sales_approx — un ratio faible (~5-10%) est normal sur Etsy
  • Concentration de niche — si un shop avec 500 ventes ne vend que des mugs chat, la niche est validée

Comparer les approches de scraping

ApprocheAvantagesInconvénientsMeilleur cas d'usage
API interne EtsyDonnées structurées, pas de parsing DOMRate limit agressif, tokens instablesRecherche rapide de mots-clés
HTML scraping (BeautifulSoup)Robuste, selecteurs stables, facile à déboguerParsing plus lent, structure pouvant changerRecherche de niche complète
HTML scraping (headless browser)Gère le JS de Cloudflare, rendu completTrès lent, coûteux en ressourcesQuand Cloudflare bloque les requêtes simples
API Etsy Open (officielle)Légal, documenté, stableAccès limité, clé API nécessaire, pas de données de ventesIntégrations d'apps partenaires

Pour la plupart des équipes POD, l'approche HTML scraping + proxies résidentiels offre le meilleur rapport coût/efficacité.

Scraping d'autocomplétion à grande échelle pour la recherche de niche

Pour cartographier les niches, vous devez interroger l'autocomplétion Etsy avec des centaines de racines de mots-clés. Voici un script optimisé avec rotation de proxies :

import requests
import time
import random
import json

# Liste de racines de mots-clés à explorer
KEYWORD_ROOTS = [
    "funny", "vintage", "custom", "personalized", "aesthetic",
    "minimalist", "boho", "cottagecore", "y2k", "cottage",
    "plant", "cat", "dog", "gaming", "coder", "nurse",
    "teacher", "mom", "dad", "bridesmaid",
]

def fetch_suggestions(root, proxy_session_id):
    """Interroge l'autocomplétion Etsy avec rotation de session proxy."""
    proxy = f"http://user-session-{proxy_session_id}-country-US:PASSWORD@gate.proxyhat.com:8080"
    proxies = {"http": proxy, "https": proxy}
    url = f"https://www.etsy.com/api/v3/ajax/member/search-suggestions?query={root}"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/125.0.0.0",
        "Accept": "application/json",
        "Referer": "https://www.etsy.com/",
    }
    try:
        resp = requests.get(url, headers=headers, proxies=proxies, timeout=15)
        if resp.status_code == 200:
            return resp.json().get("results", [])
        else:
            print(f"  Erreur {resp.status_code} pour '{root}'")
            return []
    except Exception as e:
        print(f"  Exception pour '{root}': {e}")
        return []

# Collecte des suggestions
all_suggestions = []
for i, root in enumerate(KEYWORD_ROOTS):
    # Rotation de session toutes les 10 requêtes
    session_id = f"etsy-sug-{i // 10}"
    results = fetch_suggestions(root, session_id)
    for r in results:
        all_suggestions.append(r.get("query", ""))
    print(f"{root}: {len(results)} suggestions")
    time.sleep(random.uniform(1, 3))

# Dédoublonnage et tri
unique = sorted(set(all_suggestions))
print(f"\nTotal suggestions uniques : {len(unique)}")
print(json.dumps(unique[:20], indent=2))

Ce script vous donne une liste de centaines de termes de recherche tendance. L'étape suivante est de scorer chaque terme en scrapant le nombre de résultats et le nombre de vendeurs uniques — en utilisant le premier script de ce guide.

Éthique : les vendeurs Etsy sont des petites entreprises

C'est le point le plus important de ce guide. Les vendeurs Etsy sont majoritairement des petites entreprises et des créateurs indépendants.

Règles éthiques pour le scraping Etsy :

  • Scrapez pour la recherche, pas pour la copie. Analyser les tendances de prix et les niches populaires est légitime. Copier des designs originaux et les reproduire en POD ne l'est pas.
  • Respectez robots.txt. Etsy autorise certains chemins et en bloque d'autres. Vérifiez https://www.etsy.com/robots.txt régulièrement.
  • Ne surchargez pas le serveur. Un délai de 2-5 secondes entre les requêtes est un minimum. 5-10 secondes est plus responsable.
  • Ne scrapez pas les images pour les réutiliser. Les photos de produits sont la propriété des vendeurs.
  • Conformez-vous au GDPR et au CCPA. Ne stockez pas de données personnelles de vendeurs (noms, adresses) sans nécessité.
  • Utilisez les données pour l'inspiration, pas la contrefaçon. Si un vendeur a du succès avec un concept, inspirez-vous-en pour créer votre propre version originale.

La ligne rouge : si votre scraping conduit à des produits qui sont des copies carbone de designs existants, vous avez franchi la limite éthique. La recherche de niche doit vous aider à identifier des opportunités, pas à voler le travail d'autres créateurs.

Bonnes pratiques pour un scraping Etsy fiable et durable

Gestion des proxies

  • Utilisez des proxies résidentiels rotatifs — les IPs datacenter sont immédiatement détectées
  • Ciblez les États-Unis comme pays (country-US) — Etsy sert plus de résultats aux IPs américaines
  • Rottez les sessions toutes les 30-50 requêtes pour éviter l'accumulation de signaux de bot
  • Pour les sessions longues (scraping de shop complet), utilisez des sessions sticky de 10-30 minutes

Gestion des erreurs

  • Implémentez un retry avec backoff exponentiel : 5s, 15s, 45s entre les tentatives
  • Sur un challenge Cloudflare, attendez 15 minutes minimum avant de réessayer
  • Enregistrez les IDs de listing déjà scrapés pour ne pas re-scrape en cas d'interruption
  • Utilisez un circuit breaker : si plus de 5 erreurs consécutives, pause de 30 minutes

Optimisation des performances

  • Scrapez les pages de recherche en parallèle (5-10 threads max) avec des IPs différentes
  • Scrapez les pages de détail en séquentiel avec délai — c'est là que Cloudflare est le plus sensible
  • Extrayez le maximum de données du JSON-LD avant de parser le DOM — plus rapide et plus fiable
  • Mettez en cache les résultats de recherche pendant 24h — les données changent peu

Points clés à retenir

Key Takeaways :

  • Etsy combine Cloudflare + rate limits internes — les proxies résidentiels sont obligatoires pour tout scraping sérieux
  • Privilégiez le HTML scraping avec JSON-LD pour la robustesse ; l'API interne pour les recherches rapides
  • La recherche de niche repose sur trois métriques : termes tendance (autocomplétion), concurrence (vendeurs uniques), prix moyen
  • Les badges "X Sales" sur les shops sont des estimations approximatives — utiles pour la veille, pas pour du reporting exact
  • Rottez les IPs résidentielles toutes les 30-50 requêtes et maintenez des délais de 2-5 secondes
  • Éthique avant tout : scrapez pour la recherche de niche, ne copiez jamais les designs des créateurs

Pour des proxies résidentiels optimisés pour le scraping Etsy, explorez les offres ProxyHat — rotation par pays, sessions sticky, et un pool d'IPs résidentielles dans plus de 190 pays. Consultez aussi notre guide sur le web scraping pour des stratégies avancées de rotation et de gestion d'erreurs.

Prêt à commencer ?

Accédez à plus de 50M d'IPs résidentielles dans plus de 148 pays avec filtrage IA.

Voir les tarifsProxies résidentiels
← Retour au Blog