Etsy scrapen für Niche Research: Praktischer Leitfaden für POD-Teams

Lerne, wie du Etsy-Listings, Shop-Daten und Nischen-Metriken scrapest – mit CSS/XPath-Selektoren, Rate-Limit-Strategien und Residential Proxies über ProxyHat.

Etsy scrapen für Niche Research: Praktischer Leitfaden für POD-Teams

Etsy scrapen: API-Endpunkte vs. HTML – was du wissen musst

Etsy betreibt eine öffentliche Open-API, aber sie ist seit 2022 für neue Apps praktisch geschlossen. Die rate-limits sind restriktiv (ca. 360 Requests/Minute für Lesezugriff), und wichtige Daten – Trending-Searches, Sales-Badges, Shop-Metriken – fehlen komplett. Für Niche-Research und POD-Konkurrenzanalyse bleibt HTML-Scraping der einzig realistische Weg.

Das bedeutet: Du parst gerenderte Seiten, kämpfst mit Cloudflare und musst residential IPs rotieren, damit Etsy dich nicht nach 20 Requests blockiert. Dieser Leitfaden zeigt dir genau, wie das funktioniert – mit konkreten Selektoren, Rate-Limits und ProxyHat-Konfiguration.

Etsys Seitenstruktur verstehen

Bevor du Code schreibst, musst du wissen, wo die Daten wohnen. Etsy hat vier relevante Seitentypen:

1. Suchergebnisseiten

URL-Muster: https://www.etsy.com/search?q=QUERY&ref=search_bar

  • Paginierung über &page=2, &page=3 etc.
  • Sortierung: &order=price_asc, &order=highest_review, &order=newest
  • Filter: &min_price=10&max_price=50, &ship_to=DE

Listing-Cards auf der Suchseite enthalten: Titel, Preis, Seller-Name, Bewertungsdurchschnitt, Anzahl Bewertungen, ob es ein Bestseller ist, ob kostenloses Shipping angeboten wird.

2. Listing-Detailseiten

URL-Muster: https://www.etsy.com/listing/LISTING_ID/LISTING_SLUG

Hier findest du die reichen Daten: Beschreibung, Varianten, Tags, Material, Shipping-Kosten, Verkaufszahlen (indirekt über „x sold"-Badge), Shop-Info.

3. Shop-Seiten

URL-Muster: https://www.etsy.com/shop/SHOP_NAME

Enthält: Shop-Banner, Bio, Gesamt-Verkaufszahl („X sales"), Gesamtbewertungen, Listing-Anzahl, Gründungsdatum.

4. Kategorienbaum

URL-Muster: https://www.etsy.com/c/CATEGORY_PATH

Etsy organisiert Produkte hierarchisch: JewelryRingsStatement Rings. Den Kategorienbaum kannst du über die Navigationslinks auf etsy.com/c/ rekursiv crawlen.

Anti-Bot-Maßnahmen: Cloudflare und Rate-Limits

Etsy nutzt Cloudflare als WAF – das bedeutet JavaScript-Challenges, TLS-Fingerprinting und Verhaltensanalyse. Zusätzlich hat Etsy interne Rate-Limits:

SchwellenwertVerhaltenEmpfehlung
~10-15 Requests/SekundeSoft rate-limit (HTTP 429)Max 5-8 req/s mit Pausen
~50-80 Requests/Minute von einer IPTemporärer Block (CAPTCHA-Seite)IP nach 30-40 Requests rotieren
Hunderte Requests ohne Session-KonsistenzCloudflare Challenge LoopResidential Proxies + Sticky Sessions

Warum Residential Proxies? Datacenter-IPs werden von Cloudflare fast sofort erkannt. Mobile Proxies funktionieren gut, sind aber teurer. Residential Proxies bieten das beste Preis-Leistungs-Verhältnis für Etsy – sie sehen aus wie echte Nutzer-Verbindungen.

Mit ProxyHat rotierst du residential IPs und nutzt Sticky Sessions, damit ein Crawl-Durchlauf konsistent bleibt:

# HTTP Proxy – pro Request neue IP
http://user-country-US:PASSWORD@gate.proxyhat.com:8080

# Sticky Session – gleiche IP für mehrere Requests
http://user-country-US-session-abc123:PASSWORD@gate.proxyhat.com:8080

Scraping-Patterns für Niche Discovery

Für POD-Teams sind drei Metriken besonders wertvoll:

Trending Search Terms

Etsy zeigt auf der Startseite und in der Such-Autovervollständigung Trending-Queries. Die Autovervollständigungs-API ist öffentlich:

GET https://www.etsy.com/api/v3/ajax/member/suggestions?q=cat+&lang=de

Antwort (gekürzt):

{
  "results": [
    {"query": "cat shirt", "type": "trending"},
    {"query": "cat lover gift", "type": "trending"},
    {"query": "cat mom mug", "type": "suggestion"}
  ]
}

Damit kannst du systematisch Nischen-Keywords sammeln, indem du Seed-Keywords durchiterierst.

Seller-Count pro Nische

Scrape die Suchergebnisse für ein Keyword und zähle eindeutige Shop-Namen. Wenige Seller + hohe Nachfrage = ungesättigte Nische. Viele Seller + niedrige Preise = Commoditized – vermeiden für POD.

Durchschnittliche Preis-Punkte

Extrahiere alle Preise von der Suchseite und berechne Median und Quartile. Wenn der Median für „custom cat mug" bei 22€ liegt und dein POD-Kostenpunkt bei 12€, hast du Raum für Profit.

Python-Beispiel: Suchergebnisse → Listings → Details

Hier ist ein vollständiges Beispiel, das Suchergebnisse scrapet, Listing-Cards parst und dann Detailseiten abruft – alles mit ProxyHat Residential Proxies und IP-Rotation.

import requests
from bs4 import BeautifulSoup
import time
import random
from urllib.parse import quote

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 scrape_search(keyword, max_pages=3):
    """Scrape Etsy search results for a given keyword."""
    listings = []
    for page in range(1, max_pages + 1):
        url = f"https://www.etsy.com/search?q={quote(keyword)}&page={page}"
        # Rotate IP every page via session flag
        session_id = f"niche-{keyword.replace(' ','-')}-p{page}"
        proxy = f"http://user-country-US-session-{session_id}:PASSWORD@gate.proxyhat.com:8080"
        proxies = {"http": proxy, "https": proxy}

        resp = requests.get(url, headers=HEADERS, proxies=proxies, timeout=30)
        if resp.status_code == 403:
            print(f"  Blocked on page {page}, rotating IP...")
            continue

        soup = BeautifulSoup(resp.text, "html.parser")
        cards = soup.select("div.v2-listing-card__info")

        for card in cards:
            title_el = card.select_one("h3")
            price_el = card.select_one("span.currency-value")
            seller_el = card.select_one("p.v2-listing-card__shop-name")
            rating_el = card.select_one("span.v2-listing-card__rating")

            listings.append({
                "title": title_el.text.strip() if title_el else None,
                "price": price_el.text.strip() if price_el else None,
                "seller": seller_el.text.strip() if seller_el else None,
                "rating": rating_el.text.strip() if rating_el else None,
                "listing_url": card.parent.get("href", "") if card.parent else None,
            })

        time.sleep(random.uniform(2.0, 4.5))  # respect rate limits
    return listings


def scrape_listing_detail(listing_url):
    """Scrape a single listing detail page."""
    # New IP per detail request
    proxy = f"http://user-country-US:PASSWORD@gate.proxyhat.com:8080"
    proxies = {"http": proxy, "https": proxy}

    resp = requests.get(listing_url, headers=HEADERS, proxies=proxies, timeout=30)
    soup = BeautifulSoup(resp.text, "html.parser")

    # Tags
    tags = [t.text.strip() for t in soup.select("a.tag")]

    # Sales badge (e.g. "2,415 sales")
    sales_el = soup.select_one("span[data-sales]")
    sales = sales_el.text.strip() if sales_el else None

    # Description
    desc_el = soup.select_one("div[data-appearance-id='description']")
    description = desc_el.text.strip()[:500] if desc_el else None

    return {"tags": tags, "sales": sales, "description": description}


# --- Run ---
results = scrape_search("custom cat mug", max_pages=3)
print(f"Found {len(results)} listings")

for listing in results[:5]:
    if listing["listing_url"]:
        detail = scrape_listing_detail(listing["listing_url"])
        print(f"  Tags: {detail['tags'][:5]}")
        print(f"  Sales: {detail['sales']}")
        time.sleep(random.uniform(1.5, 3.5))

Wichtige Hinweise:

  • Die CSS-Klassen (v2-listing-card__info, currency-value etc.) können sich ändern. Immer zuerst manuell im Browser prüfen.
  • Verwende Sticky Sessions für Paginierung, damit deine Session konsistent bleibt.
  • Pausen von 2-4 Sekunden zwischen Requests sind Pflicht – Etsy ist aggressiver als Amazon.

Shop-Analytics: Sales, Listings und Reviews

Shop-Daten sind Gold für POD-Research. Etsy zeigt Verkaufszahlen als grobe Badge an („1,234 sales"), was ausreicht, um Shop-Größen zu schätzen.

Verfügbare Shop-Metriken

  • Sales Count: XPath //span[contains(@class,'shop-sales')] oder CSS span.shop-sales
  • Listing Count: Auf der Shop-Seite unter dem Shop-Namen sichtbar
  • Review Count & Durchschnitt: CSS span.review-count, input[name='rating']
  • Gründungsdatum: Meist im Footer der Shop-Seite als „Since YYYY"

Shop-Scraping-Funktion

def scrape_shop(shop_name):
    """Scrape Etsy shop metrics."""
    url = f"https://www.etsy.com/shop/{shop_name}"
    session_id = f"shop-{shop_name}"
    proxy = f"http://user-country-US-session-{session_id}:PASSWORD@gate.proxyhat.com:8080"
    proxies = {"http": proxy, "https": proxy}

    resp = requests.get(url, headers=HEADERS, proxies=proxies, timeout=30)
    soup = BeautifulSoup(resp.text, "html.parser")

    # Sales badge
    sales_el = soup.select_one("span.shop-sales")
    sales_text = sales_el.text.strip() if sales_el else "0"
    # Parse "1,234 sales" → 1234
    sales_num = int(sales_text.lower().replace("sales", "").replace(",", "").strip() or "0")

    # Review count
    review_el = soup.select_one("span.review-count")
    review_count = review_el.text.strip() if review_el else "0"

    # Number of listings (from shop tab or pagination)
    listing_count_el = soup.select_one("span.listings-count")
    listing_count = listing_count_el.text.strip() if listing_count_el else "unknown"

    return {
        "shop": shop_name,
        "sales": sales_num,
        "reviews": review_count,
        "listing_count": listing_count,
    }


# Example: analyze top sellers in a niche
shops_seen = set()
for listing in results:
    seller = listing.get("seller")
    if seller and seller not in shops_seen:
        shops_seen.add(seller)
        shop_data = scrape_shop(seller)
        print(f"{seller}: {shop_data['sales']} sales, {shop_data['listing_count']} listings")
        time.sleep(random.uniform(3.0, 6.0))

Was du aus Shop-Metriken lernst

  • High Sales + Low Listings: Der Seller hat wenige Produkte, die aber extrem gut verkaufen → Nische mit hoher Conversion.
  • High Sales + High Listings: Volume-Seller – gute Inspiration für Katalog-Breite, aber schwer zu schlagen.
  • Low Sales + High Listings: Seller kämpft – Nische könnte übersättigt sein.

Proxy-Strategie im Vergleich

Proxy-TypEtsy-ErfolgsrateKostenBest für
Datacenter10-20% (Cloudflare blockiert)NiedrigNicht empfohlen für Etsy
Residential (rotierend)85-95%MittelBulk-Scraping, Suchseiten
Residential (Sticky Session)90-98%MittelPaginierte Crawl-Durchläufe
Mobile95-99%HochMaximale Zuverlässigkeit, niedriges Volumen

Für die meisten POD-Research-Use-Cases sind Residential Proxies mit Sticky Sessions optimal. Sie sind bezahlbar und liefern konsistente Sessions, die für Paginierung nötig sind. Sieh dir die ProxyHat-Preise an, um den richtigen Plan zu finden.

Ethik: Etsy-Seller sind kleine Unternehmen

Dieser Punkt ist wichtig und wird oft übersehen. Etsy-Seller sind überwiegend Einzelpersonen und kleine Familienbetriebe – nicht Amazon-Warehouse-Fulfillment-Zentren.

Was in Ordnung ist

  • Nischen-Research: Analysieren, welche Keywords Nachfrage haben, wo Preis-Lücken existieren, welche Tags konvertieren.
  • Marktanalyse: Seller-Counts, Preisverteilungen, Trending-Begriffe sammeln.
  • Konkurrenz-Beobachtung: Verstehen, wie erfolgreiche Shops ihre Listings strukturieren.

Was nicht in Ordnung ist

  • Designs kopieren: Ein Seller hat ein einzigartiges Design → du kopierst es 1:1 auf dein POD-Store.
  • Bilder stehlen: Listing-Bilder herunterladen und als eigene Listings verwenden.
  • Massenhaft Daten abrufen: Ganze Kategorien mit Tausenden Listings scrapen, nur um sie zu replizieren.

Scrape für Erkenntnisse, nicht für Diebstahl. Die Daten sind da, um dich zu inspirieren und zu informieren – nicht, um kreative Arbeit zu stehlen.

Praktische Ethik-Regeln

  • Respektiere robots.txt – Etsy erlaubt einige Pfade, verbietet andere.
  • Rate-limit dich selbst: Max 5-8 Requests/Sekunde, Pausen zwischen Seiten.
  • Scrape nur so viel wie du brauchst – nicht ganze Kategorien „just because".
  • Speichere keine Bilder, es sei denn, du analysierst Bildformate für eigene Listings.
  • Wenn du Daten weitergibst, anonymisiere Seller-Namen in veröffentlichten Berichten.

Rate-Limit-Strategien in der Praxis

Hier ist ein Muster, das Backoff und IP-Rotation kombiniert:

import requests
import time
import random
from itertools import cycle

class EtsyScraper:
    def __init__(self, proxy_user, proxy_pass):
        self.base_proxy = f"http://{proxy_user}:{{session}}@gate.proxyhat.com:8080"
        self.proxy_pass = proxy_pass
        self.session_counter = 0

    def _get_proxy(self, sticky=False):
        if sticky:
            session = f"{self.proxy_user}-session-s{self.session_counter}"
        else:
            self.session_counter += 1
            session = f"{self.proxy_user}-session-r{self.session_counter}"
        proxy_url = self.base_proxy.format(session=session).replace(
            "{session}", session
        )
        # Build correct proxy URL
        proxy_url = f"http://{session}:{self.proxy_pass}@gate.proxyhat.com:8080"
        return {"http": proxy_url, "https": proxy_url}

    def fetch_with_retry(self, url, max_retries=3, sticky=False):
        for attempt in range(max_retries):
            proxies = self._get_proxy(sticky=sticky)
            try:
                resp = requests.get(
                    url, headers=HEADERS, proxies=proxies, timeout=30
                )
                if resp.status_code == 200:
                    return resp
                elif resp.status_code == 429:
                    wait = (2 ** attempt) + random.uniform(1, 5)
                    print(f"  Rate-limited, waiting {wait:.1f}s...")
                    time.sleep(wait)
                elif resp.status_code == 403:
                    print(f"  Blocked (403), rotating IP...")
                    time.sleep(random.uniform(2, 5))
                else:
                    print(f"  HTTP {resp.status_code}, retrying...")
                    time.sleep(2)
            except requests.exceptions.RequestException as e:
                print(f"  Request failed: {e}")
                time.sleep(3)
        return None


# Usage
scraper = EtsyScraper(proxy_user="user-country-US", proxy_pass="PASSWORD")
resp = scraper.fetch_with_retry("https://www.etsy.com/search?q=custom+cat+mug")

Key Takeaways

  • Etsys API ist de facto geschlossen – HTML-Scraping bleibt der einzige Weg für Niche-Research.
  • Cloudflare + interne Rate-Limits machen Residential Proxies obligatorisch; Datacenter-IPs funktionieren nicht.
  • Sticky Sessions sind für paginierte Crawl-Durchläufe essenziell – rotiere IPs alle 30-40 Requests.
  • Konzentriere dich auf drei Metriken: Seller-Count pro Nische, durchschnittliche Preis-Punkte, Trending-Search-Terms.
  • Shop-Sales-Badges geben dir grobe Verkaufszahlen – genug für Größenordnungen und Competitive-Analyse.
  • Ethisch scrapen: Nischen finden, Designs nicht kopieren. Etsy-Seller sind kleine Unternehmen.
  • Rate-limit dich selbst: Max 5-8 req/s, Pausen von 2-4 Sekunden, Backoff bei 429/403.

Wenn du bereit bist, Etsy-Nischen systematisch zu analysieren, starte mit ProxyHat Residential Proxies auf dem Dashboard und baue deine Niche-Research-Pipeline auf. Weitere Scraping-Strategien findest du in unserem Web-Scraping-Use-Case und SERP-Tracking-Leitfaden.

Bereit loszulegen?

Zugang zu über 50 Mio. Residential-IPs in über 148 Ländern mit KI-gesteuerter Filterung.

Preise ansehenResidential Proxies
← Zurück zum Blog