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=3etc. - 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: Jewelry → Rings → Statement 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:
| Schwellenwert | Verhalten | Empfehlung |
|---|---|---|
| ~10-15 Requests/Sekunde | Soft rate-limit (HTTP 429) | Max 5-8 req/s mit Pausen |
| ~50-80 Requests/Minute von einer IP | Temporärer Block (CAPTCHA-Seite) | IP nach 30-40 Requests rotieren |
| Hunderte Requests ohne Session-Konsistenz | Cloudflare Challenge Loop | Residential 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-valueetc.) 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 CSSspan.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-Typ | Etsy-Erfolgsrate | Kosten | Best für |
|---|---|---|---|
| Datacenter | 10-20% (Cloudflare blockiert) | Niedrig | Nicht empfohlen für Etsy |
| Residential (rotierend) | 85-95% | Mittel | Bulk-Scraping, Suchseiten |
| Residential (Sticky Session) | 90-98% | Mittel | Paginierte Crawl-Durchläufe |
| Mobile | 95-99% | Hoch | Maximale 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.






