---
title: "Etsy scrapen: Leitfaden 2026"
slug: how-to-scrape-etsy
date: 2026-02-16T07:45:29+00:00
modified: 2026-09-16T12:00:24+00:00
permalink: https://brightdata.de/blog/web-data-de/how-to-scrape-etsy
type: blog
---

[ Blog ](https://brightdata.de/blog "Blog") / [Web Data](https://brightdata.de/blog/web-data-de)







 [Web Data](https://brightdata.de/blog/web-data-de)

# Etsy scrapen: Leitfaden 2026

Etsy betreibt DataDome und hat alle 9 Transportwege, die wir getestet haben, abgelehnt. Erfahren Sie, was robots.txt erlaubt, was einen Datensatz beschädigt und wann Bright Data besser passt.

 18 min lesen





 [ ![Jacob Nulty](https://media.brightdata.de/2024/12/Jacob-Nulty-50x50.jpg) ](https://brightdata.com/blog/authors/jake-nulty)

 [Jake Nulty

Technical Writer

 ](https://brightdata.com/blog/authors/jake-nulty)





 ![How to Scrape Etsy blog image](https://media.brightdata.de/2025/02/How-to-Scrape-Etsy.svg)





Etsy scrapen bedeutet, Listing-, Shop- und Bewertungsdaten von öffentlichen Etsy-Seiten zu erfassen. Etsy meldete [mehr als 100 Millionen Artikel und 5,6 Millionen aktive Verkäufer](https://www.sec.gov/Archives/edgar/data/1370637/000137063726000019/etsy-20251231.htm) im Jahresbericht 2025. Etsy setzt DataDome ein. Eine direkte Anfrage gibt einen 403-Fehler und eine Blockseite zurück. Die 2 häufigsten Lösungsansätze sind ein Chrome User-Agent und TLS-Impersonation. Beide führen weiterhin zu einem 403. Dieser Leitfaden zeigt, was den 403-Fehler behebt, was robots.txt blockiert und welche Extraktionsprobleme einen Etsy-Datensatz beschädigen, ohne einen Fehler auszulösen.

## TL;DR

- Etsy betreibt DataDome hinter Fastly. DataDome schreibt einen Risikoscore in seinen eigenen Response-Header. Damit lässt sich eine Anfrage bewerten, bevor man einen Crawler entwickelt.
- Etsy hat alle 9 Transportwege abgelehnt, die wir getestet haben. Ein headed Browser lud die erste Seite in 2,2 Sekunden. Die zweite Anfrage wurde von Etsy abgelehnt.
- robots.txt verbietet die Keyword-Suche und die Verkaufshistorie und deklariert keinen Sitemap. Listing- und Shop-Seiten blieben dort offen. Etsys Nutzungsbedingungen sind jedoch strenger.
- Währung und Preis richten sich nach der Exit-IP. Unser Datensatz-Sample enthielt 19 Währungen. Ein ungefilterter Durchschnitt dieser Spalte war 227-mal zu hoch.

## Was Etsy auf eine automatisierte Anfrage zurückgibt

Lesen Sie zuerst die Ablehnung. Wiederholen Sie die Anfrage nicht. Eine einfache Anfrage zeigt, welcher Anbieter am Edge läuft und wie dieser Anbieter Sie bewertet hat. Jede Listing-URL funktioniert. Diese gehört einem Verkäufer und ist möglicherweise bereits nicht mehr verfügbar:

```none
curl -sD - -o /dev/null https://www.etsy.com/listing/753913297/smoky-quartz-ring-rose-gold-ring-women
```

Der Server gibt einen 403-Fehler mit diesen Headern zurück:

```none
HTTP/2 403
server: DataDome
x-datadome: protected
x-datadome-riskscore: 0.9230727100377928
accept-ch: Sec-CH-UA,Sec-CH-UA-Mobile,Sec-CH-UA-Platform,Sec-CH-UA-Arch,Sec-CH-UA-Full-Version-List,Sec-CH-UA-Model,Sec-CH-Device-Memory
set-cookie: datadome=ovuDEZ4S0taK1jDAOvZ9W3Uq2qUujN_iPPE3uXp7~r3msKXSvMFPp4j30em5IvR0...
via: 1.1 varnish
x-served-by: cache-del-vibw2260027-DEL
```

Dieser Block enthält 3 Fakten. Etsy verwendet DataDome, nicht den Akamai Bot Manager, den ältere Leitfäden noch erwähnen, also plant man gegen DataDomes [Erkennungsschichten](/blog/web-data/anti-scraping-techniques). Fastly läuft vor Etsy, und die `Via`– und `X-Served-By`-Header zeigen diesen Hop. `X-DataDome-riskscore` ist DataDomes Score dafür, wie bot-ähnlich die Anfrage wirkte, auf einer Skala, bei der 1,0 der schlechteste Wert ist. Etsy kann Anbieter wechseln, also führen Sie den Befehl erneut aus, bevor Sie gegen diese 3 Fakten planen.

Dieser Header gibt Ihnen eine Zahl zum Messen. In unseren Tests war der Score deterministisch. Alle 6 verschachtelten Samples derselben Anfrage gaben `0.9230727100377928` zurück. Der Score verfolgt die Anfrage-Signatur, die aufrufende IP und den `datadome`-Cookie, sobald Sie einen zurücksenden, nicht eine laufende Zählung von Anfragen. Ihre eigenen Zahlen können also abweichen, und bei einer anderen Adresse kann das Ranking zwischen Client-Konfigurationen ebenfalls abweichen.

Der Body, 776 Bytes in unseren Läufen, ist eine DataDome-Blockseite, die `ct.captcha-delivery.com/c.js` lädt. Diese Blockseite enthält ein Challenge-Skript, keine Listing-Daten, sodass ein Parser, der sie liest, leere Felder statt eines Fehlers zurückgibt. Die eingebettete Konfiguration enthielt `'t':'fe'`, DataDomes Geräteprüfung, sodass dieser Fetch eine Challenge erhielt, die ein echter Browser beantworten kann, statt eines dauerhaften Bans. Das `'t'`-Feld zeigt die aktuelle Bewertung und nimmt andere Werte an, wenn sich diese ändert, also lesen Sie Ihren eigenen Wert, statt `'fe'` anzunehmen.

Wir haben jede Anfrage von 1 minimalen 3-Header-Client gesendet und nur den Pfad variiert. Jeder Inhaltspfad, den wir versuchten, gab denselben 403 und denselben 0,482-Score zurück, während `/robots.txt` und eine URL, die zu nichts auflöst, ungeschützt zu Apache gingen:

```none
path                                       HTTP server     riskscore
/                                          403  DataDome   0.482
/listing/753913297/smoky-quartz-ring...    403  DataDome   0.482
/shop/AnemoneJewelry                       403  DataDome   0.482
/legal/terms/                              403  DataDome   0.482
/robots.txt                                200  Apache     -
/nonexistent-path-xyz                      404  Apache     -
```

Auf den von DataDome geschützten Pfaden bewertet es also den Aufrufer und nicht die URL.

Eine Anfrage mit einem Googlebot User-Agent umging DataDome und erreichte stattdessen einen Rate-Limiter. Apache antwortete mit `429 Too Many Requests` und einem `nicki_`-Referenzstring. Mindestens 1 deklarierter Suchmaschinen-Agent erreicht einen eigenen Rate-Limiter, getrennt von DataDome.

## Warum Header und TLS-Fingerprints nicht ausreichen

Der Risikoscore ermöglicht es, den üblichen Rat zu Headern zu testen, wobei eine niedrigere Zahl weniger bot-ähnlich bedeutet. Wir hielten IP und URL konstant, variierten nur die Request-Header eines `requests`-Clients und notierten den von DataDome zurückgegebenen Score:

```none
headers sent                                         score    HTTP
requests, library default headers                    0.977    403
+ Chrome User-Agent only                             0.923    403
full 12-header Chrome set                            0.503    403
User-Agent + accept + sec-fetch-site (3 headers)     0.482    403
```

Diese Tabelle enthält 2 Ergebnisse. Das Hinzufügen eines Chrome User-Agents hat die Bewertung kaum verändert, weil alles andere in der Anfrage immer noch von `requests` stammte. Und das 3-Header-Set erzielte einen *besseren* Score als das vollständige 12-Header-Set, daher war bei diesem Ziel Konsistenz wichtiger als die Header-Anzahl.

Diese 3 Header erzielten 0,482, also kopieren Sie den `accept`-Wert exakt:

```none
User-Agent:      Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36
                 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36
accept:          text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,
                 image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
sec-fetch-site:  none
```

Wir haben jeweils 1 Header aus dem vollständigen Set entfernt und jede Änderung notiert, wobei ein Pluszeichen bedeutet, dass der Score schlechter wurde:

```none
run                              score     change
full set (baseline)              0.503
minus accept                     0.845     +0.342
minus user-agent                 0.784     +0.281
minus sec-fetch-site             0.669     +0.166
minus every sec-ch-ua* header    0.503      0.000
```

DataDome bewirbt 7 Client-Hints in seinem eigenen `Accept-CH`-Response-Header. Unser vollständiges Set hatte 3 davon, aber das Entfernen aller `sec-ch-ua`-Header änderte nichts. Der `accept`-Header bewegte den Score stärker als der User-Agent.

[TLS-Impersonation](/blog/web-data/web-scraping-with-curl-impersonate) ist der übliche nächste Schritt, also haben wir sie allein getestet. Jeder Lauf sendete dieselben 3 Header, und nur der TLS- und HTTP/2-Fingerprint änderte sich. Die JA4-Werte unten stammen aus `curl_cffi` und nicht von Etsy, daher ändern sie sich, wenn diese Bibliothek ein Profil aktualisiert:

```none
transport                             JA4                      riskscore  HTTP
python requests (OpenSSL, HTTP/1.1)   t13d1712h1_ab0a1bf427ad  0.482      403
curl_cffi impersonate=chrome110       t13d1516h2_8daaf6152771  0.663      403
curl_cffi impersonate=chrome116       t13d1516h2_8daaf6152771  0.663      403
curl_cffi impersonate=chrome124       t13d1516h2_8daaf6152771  0.503      403
curl_cffi impersonate=chrome131       t13d1516h2_8daaf6152771  0.503      403
curl_cffi impersonate=chrome133a      t13d1516h2_8daaf6152771  0.503      403
curl_cffi impersonate=firefox133      t13d1716h2_5b57614c22b0  0.503      403
curl_cffi impersonate=safari17_0      t13d2014h2_a09f3c656075  0.663      403
curl_cffi impersonate=safari17_2_ios  t13d2014h2_a09f3c656075  0.663      403
```

Diese Tabelle enthält 3 verschiedene Fingerprints, je einen für Chrome, Firefox und Safari. Einfaches `requests` über HTTP/1.1 erzielte immer noch einen besseren Score als alle 3. Diese Spalte gibt nur die ersten 2 Teile eines JA4 aus. Der dritte Teil kodiert die Erweiterungsliste und unterscheidet sich zwischen den Chrome-Profilen, die hier ein Präfix teilen.

Der Transport bewegte den Score zwischen dem besten und schlechtesten Lauf um 0,181, aber kein Lauf gab eine Seite zurück. Kein Fingerprint, den wir getestet haben, reichte allein aus.

Also lohnen sich [TLS-Fingerprints](/blog/web-data/tls-fingerprinting) bei diesem Ziel nicht. Wir haben die HTTP/2-Frames von jedem Profil zurückgelesen, einschließlich der Pseudo-Header-Reihenfolge, die sich je nach Engine unterscheidet:

```none
profile      SETTINGS                       | window   | pri | pseudo-header order
chrome131    1:65536;2:0;4:6291456;6:262144 | 15663105 | 0   | m,a,s,p
firefox133   1:65536;2:0;4:131072;5:16384   | 12517377 | 0   | m,p,a,s
safari17_0   2:0;4:4194304;3:100            | 10485760 | 0   | m,s,p,a
```

Diese 3 Handshakes sind korrekte Kopien, und Etsy hat alle 3 abgelehnt. DataDome entscheidet also anhand von etwas anderem als dem Handshake.

## Was die Prüfung tatsächlich ausführt

In einem headed Browser rendert DataDomes Challenge als Slider, und 2 der 4 Gründe sind die aufrufende IP und die Verwendung von Entwicklertools:

![Etsys DataDome-Challenge-Seite. Eine Überschrift lautet 'Verification Required' über einem Widget mit der Aufschrift 'Slide right to secure your access' mit einem Ziehgriff, einem Bild-oder-Audio-Umschalter und einer Aktualisierungssteuerung. Darunter eine Grundliste: schnelle Taps oder Klicks, JavaScript deaktiviert oder nicht funktionsfähig, automatisierte Aktivität in Ihrem Netzwerk mit geschwärzter IP und Verwendung von Entwickler- oder Inspektionstools](https://media.brightdata.com/2026/09/HyEfP28Yzg.png)Dieser `c.js`-Loader ist 14 KB groß, erstellt eine iframe-URL und ruft eine zweite Seite ab. Diese zweite Seite enthielt an dem Tag, an dem wir sie abgerufen haben, ein 596 KB großes Inline-Skript, und seine Modulnamen zeigen, was man reimplementieren müsste:

```none
detection-js/dist/vm-obf.js     the detection engine, VM-obfuscated
detection-js/dist/captcha.js    challenge coordination
./picasso                       canvas-based device-class fingerprinting
./mouseMaths                    pointer-movement analysis
./slidercaptcha  ./hash  ./helpers  ./bean
```

Das Erkennungsmodul wird als Bytecode für einen im selben File gebündelten Interpreter gespeichert. Deshalb findet eine Textsuche im Bundle weder `webdriver`, noch `cdc_`, noch `headless`, noch `_phantom`. Ein Bytecode-Bundle verbirgt diese Strings, egal ob die Probes laufen oder nicht, sodass das Suchergebnis nichts aussagt.

Der Build, den wir abgerufen haben, meldete sich selbst als `1.34.0`, maß seine eigene Ausführungszeit und sendete diese Dauer als Signal. Dieser Build protokollierte auch eine Konsolenwarnung, die Sie aufforderte, DevTools zu schließen, bevor Sie fortfahren. Erwarten Sie eine andere Version und eine andere Modulliste, wenn Sie nachschauen, da diese Engine dem Release-Zyklus von DataDome und nicht dem von Etsy folgt. Die Architektur hinter diesen Namen ändert sich weit langsamer.

Die Check-Anfrage hat 16 Felder und kodiert die Browser-Umgebung in `userEnv`, `ddCaptchaEnv` und `plv3`.

Es gibt also 2 praktische Schlussfolgerungen. Diesen Output aus `requests` zu reproduzieren bedeutet, eine obfuskierte VM gegen einen Versionsstring reimplementieren zu müssen, der sich erhöht. Und DataDome sammelt Canvas-Output und Zeigerbewegungen, die nur existieren, nachdem eine echte Browser-Engine die Seite gerendert hat. [DataDome-spezifisches Entsperren](/products/web-unlocker/captcha-solver/datadome) betreibt diese Browser-Engine als Dienst und ist darauf ausgelegt, die gerenderte Seite zurückzugeben statt des Blocks.

Diese zweite Schlussfolgerung ist testbar, also haben wir einen einfachen Playwright Chromium ohne Stealth-Patches und ohne Proxy ausgeführt. Jeder Modus wurde 3 Mal von derselben Adresse aus gestartet, von der alle oben genannten Transporte abgelehnt wurden:

```none
headless=True (default)        403  403  403     1,530 B    0.5s
headless=True --headless=new   403  403  403     1,530 B    0.4s
headless=False (headed)        200  200  200   532,049 B    2.2s   Product JSON-LD present
```

Beide Fenster liefen von 1 Maschine ohne Proxy, sodass das headed Fenster Preise in der lokalen Währung anzeigt:

![Zwei Chromium-Fenster nebeneinander. Das headless-Fenster zeigt Etsys Blockseite mit der Aufschrift 'Access is temporarily restricted' über einer Liste von Gründen einschließlich automatisierter Aktivität im Netzwerk. Das headed Fenster zeigt die vollständige Listing-Seite mit Produktfoto, Preis, Variations-Dropdowns und einer Schaltfläche 'In den Warenkorb'](https://media.brightdata.com/2026/09/B1PQvhLFMg.png)Headless Chromium enthält `HeadlessChrome` in seinem eigenen User-Agent, sodass sich diese Zeilen in mehr als dem Fenster unterscheiden. Für die manuelle Überprüfung einer Seite oder das Abrufen einiger weniger Seiten ist ein headed Browser die einfachste Antwort. [Entsperr-Infrastruktur](https://docs.brightdata.com/concepts/how-bright-data-handles-blocking) ist für die Anfragen nach der ersten ausgelegt, und für einen einzelnen Fetch ist ein headed Lauf etwa 10 Mal schneller als die Weiterleitung durch sie.

## Warum ein Browser kein Crawler ist

Wir haben 12 Listings nacheinander in einer einzigen Browser-Seite geladen, 2 Sekunden auseinander, und 1 Erfolg und 11 Ablehnungen erhalten:

```none
#1   200   444,123 B
#2   403     1,527 B
#3-12 403   ~1,530 B each
```

Das Verwerfen des Browsing-Kontexts zwischen Navigationen stellte den 200-Status wieder her, sodass die Ablehnungen aus dem Session-Zustand und nicht aus der Adresse kamen. Später im selben Testzeitraum hörte diese Lösung auf zu funktionieren. Etsy lehnte dann jede Anfrage von dieser Adresse ab, unabhängig davon, wie neu der Kontext war.

Der Risikoscore bewegte sich nicht, während die Erfolgsrate von jeder Anfrage auf keine sank. Der 3-Header-Lauf maß noch immer `0.4822` auf 4 Dezimalstellen, Stunden und mehrere hundert Anfragen nach dem ersten Messwert.

Der `X-DataDome-riskscore`-Header bewertet 1 Anfrage gleichzeitig, ist also nützlich zum Testen einer Änderung, aber nicht zum Überwachen eines Crawls. Eine Pipeline, die ihn beobachtet, meldet Erfolg, während sie nichts sammelt.

Für das Sammeln von mehr als einigen wenigen Seiten sind 2 Dinge erforderlich: ein neuer Browsing-Kontext und eine Adresse, die DataDome noch nicht abgelehnt hat. Das Verwerfen des Kontexts zwischen Navigationen ist günstig, also beginnen Sie dort, aber diese Lösung hält nur an, bis DataDome die Adresse ablehnt. [Residential-Proxys](/proxy-types/residential-proxies) bieten Ihnen einen Pool von Adressen zum Rotieren.

[Web Unlocker](/products/web-unlocker) führt beides aus, und das Skript weiter unten bleibt im kostenlosen Kontingent. [Browser API](/products/scraping-browser/playwright) verarbeitet beides in einem gehosteten Browser, den Ihr Playwright-Code steuert.

## Was robots.txt und die Etsy-Nutzungsbedingungen nicht erlauben

Lesen Sie [Etsys robots.txt](https://www.etsy.com/robots.txt) selbst, bevor Sie etwas aufbauen, da die Datei die Keyword-Suche verbietet und Etsy sie ohne Ankündigung neu schreibt. Als wir sie lasen, war diese Datei 1.818 Zeilen lang und deklarierte nur 3 User-Agent-Gruppen: `*`, `AdsBot-Google-Mobile` und `Spinn3r`:

```none
User-agent: *
Disallow: /search?*q=
Disallow: /search/?*q=
Disallow: */shop/*/sold*
Disallow: */listing/*/favoriters*
Disallow: /api/
Allow:    /search/shops
```

Die Wildcard-Gruppe verbietet Keyword-Suchergebnisse in jeder Locale-Variante. Diese Gruppe umfasst jeden Crawler, den die anderen 2 Gruppen nicht namentlich nennen. Auch die Verkaufshistorie und Favoriten-Zahlen sind verboten, und sie gehören zu den klarsten Nachfragesignalen, die Etsy veröffentlicht. Listing-Seiten und Shop-Seiten haben keine Disallow-Regel, sodass beide offen bleiben.

Die Datei deklariert keine `Sitemap:`-Direktive, und `/sitemaps.xml` antwortet mit 403 und leerem Body. Diese 2 Abwesenheiten sind genauso wichtig wie die Disallow-Regeln oben. Beide sind 1-Zeilen-Prüfungen, die es wert sind, wiederholt zu werden, da Etsy beides ohne Ankündigung wieder hinzufügen kann. Solange sie fehlen, müssen Sie Listings von den Seiten entdecken, die Etsy offen lässt.

Etsy nannte in der Datei, als wir sie lasen, keinen KI-Crawler und veröffentlichte weder `llms.txt` noch `ai.txt`. Diese Abwesenheit ist das Wahrscheinlichste in diesem Abschnitt, das sich seit unserer Prüfung geändert haben könnte.

DataDome lehnt diese Crawler am Edge ab, unabhängig davon. GPTBot und ClaudeBot erhielten beide einen 403-Fehler und erzielten in unserem Test beide 0,9814, höher als die 0,923, die dieselbe Adresse mit einem Chrome User-Agent erzielte. Sinnlose User-Agent-Strings mit denselben Headern erzielten denselben Score, also bewertet DataDome die Abwesenheit eines bekannten Browsers und nicht den Crawler-Namen.

Die [Etsy-Nutzungsbedingungen](https://www.etsy.com/legal/terms-of-use/), zuletzt aktualisiert am 26. August 2025, besagen, dass Sie zustimmen, “keine Seite der Dienste zu crawlen, zu scrapen oder zu spidern” ohne ausdrückliche Genehmigung.

Prüfen Sie, ob Ihre Collection-Schicht robots.txt für Sie durchsetzt und zu welchem Zeitpunkt sie entscheidet. Der Residential-Entsperr-Endpunkt entscheidet pro Anfrage. Bei einem Konto ohne abgeschlossene KYC-Überprüfung gibt eine Anfrage für den verbotenen Suchpfad die Regel und das KYC-Formular zurück:

```none
Residential Failed (bad_endpoint): Requested site is not available for immediate
residential (no KYC) access mode in accordance with robots.txt. To get full
residential access for targeting this site, fill in the KYC form:
https://brightdata.com/cp/kyc
```

Dasselbe Konto rief `/shop/AnemoneJewelry` ohne Fehler ab, und die Antwort war 983.937 Bytes groß. Der Endpunkt liest dieselbe robots.txt wie Sie, bedient dann die erlaubten Pfade und leitet die verbotenen Pfade zur Compliance-Überprüfung statt zu einem Proxy weiter. Entscheiden Sie, ob Ihr Anwendungsfall die verbotenen Pfade benötigt, bevor Sie mit dem Aufbau beginnen.

Wenn Sie die Fetch-Schicht selbst aufbauen, treffen Sie diese Entscheidung im Code und sind für die [robots.txt-Verarbeitung](/blog/how-tos/robots-txt-for-web-scraping-guide) pro Ziel verantwortlich und müssen sie pflegen.

## Was die offizielle Etsy-API zurückgibt und was sie weglässt

Die API ist der autorisierte Weg, also prüfen Sie, was sie tut, bevor Sie sie ablehnen. Die [Wahl zwischen einer offiziellen API und Web-Scraping](/blog/web-data/web-scraping-vs-api) ist allgemein, und bei Etsy hängt sie von den Feldern ab, die die Spezifikation weglässt. Wir haben die [OpenAPI-Spezifikation](https://www.etsy.com/openapi/generated/oas/3.0.0.json) direkt abgerufen und 76 Pfade gezählt, von denen 31 GET-Operationen nur einen Anwendungsschlüssel und kein Verkäufer-OAuth benötigen. Diese Gesamtzahlen ändern sich, wenn Etsy einen Endpunkt hinzufügt oder entfernt, also zählen Sie aus dieser Datei neu und nicht aus diesem Absatz.

Gängige Behauptungen über die v3-API sind in 3 Punkten falsch. `findAllListingsActive` wurde nicht entfernt und akzeptiert `keywords`, `min_price`, `max_price`, `taxonomy_id`, `shop_location`, `currency` und `buyer_country`, mit einem maximalen `limit` von 100 pro Aufruf. `getReviewsByListing` und `getReviewsByShop` geben Bewertungstext nur mit einem App-Key zurück. `getShop` gibt `transaction_sold_count`, `review_count`, `review_average`, `num_favorers` und `listing_active_count` für jeden Shop zurück.

Die Spezifikation enthält 1 Nachfragefeld und lässt den Rest weg. `getListing` benötigt nur einen Anwendungsschlüssel und gibt `views` zurück, eine kumulative Aufrufsanzahl, die einmal täglich aktualisiert wird, im `ShopListingWithAssociations`-Schema. Eine Suche im gesamten Dokument ergibt kein Feld für Suchvolumen, Impressionen, Konversionsrate oder Verkäufe pro Listing. Das `ShopListing`-Schema hatte 50 Eigenschaften, als wir zählten, einschließlich `num_favorers`, `quantity` und `price`, und keine davon war eine Verkaufsanzahl. Überprüfen Sie die Zahl anhand der Spezifikation, aber bisher ist kein Verkaufsfeld erschienen.

Transaktionen pro Listing haben zwar einen Endpunkt, `getShopReceiptTransactionsByListing`, aber er benötigt den `transactions_r`-OAuth-Scope, den nur ein Shop-Inhaber für seinen eigenen Shop gewähren kann. Für jeden Shop, den Sie nicht betreiben, veröffentlicht Etsy Lifetime-Verkäufe auf Shop-Ebene als aktuelle Gesamtsumme ohne Historie und nichts pro Listing.

Diese Lücke erklärt den Drittanbieter-Tool-Markt rund um Etsy. Einige Produkte verkaufen Verkaufsschätzungen pro Listing oder Keyword-Suchvolumen für Shops, die sie nicht betreiben. Nichts in der Spezifikation, die wir gelesen haben, gibt diese Zahlen für einen Shop zurück, den Sie nicht besitzen, also müssen diese Daten von außerhalb dieser API stammen.

Etsy setzt Rate-Limits pro Anwendungsschlüssel, pro Sekunde und pro Tag durch. Die `x-limit-per-second`– und `x-limit-per-day`-Response-Header melden beides, und Etsy gibt einen 429 mit einem `retry-after` zurück, wenn Sie eines überschreiten.

Die [Rate-Limits-Seite](https://developers.etsy.com/documentation/essentials/rate-limits) kennzeichnet ihre Zahlen als “Beispielwert” und nicht als Standards. Das ältere Paar “10.000 pro Tag, 10 pro Sekunde” war von dieser Seite verschwunden, als wir sie lasen. Lesen Sie Ihre eigenen Limits aus dem Developer Portal.

## Etsy-Listing- und Shop-Seiten mit Python scrapen

Etsy-Listing-Seiten betten schema.org JSON-LD ein, sodass der Extraktionsschritt keine CSS-Selektoren benötigt und nicht bricht, wenn Etsy das Markup drum herum neu gestaltet. Der Fetch-Schritt benötigt Infrastruktur, und Sie haben 2 Möglichkeiten. Eine entsperrte API läuft überall und benötigt ein Konto. Ein lokaler Browser benötigt kein Konto und eignet sich für einige wenige Seiten.

Das folgende Skript benötigt 1 Bibliothek und 2 Umgebungsvariablen:

```none
python3 -m venv .venv && source .venv/bin/activate
pip install requests
export BRIGHTDATA_API_KEY="your-api-token"
export BRIGHTDATA_ZONE="web_unlocker"
```

Das Token stammt aus dem Bright Data Control Panel. Jede Anfrage mit diesem Token verbraucht Ihr Kontoguthaben, also halten Sie es in einer Umgebungsvariablen statt in einem committeten Skript.

Sie erstellen den zweiten Wert unter **Web Access → Add API → Web Unlocker API**. Die Anfrage-Payload nennt es eine `Zone`, aber das Control Panel bezeichnete es als API, als wir das einrichteten, daher fand eine Suche im Panel nach “Zone” nichts. `BRIGHTDATA_ZONE` muss mit dem Namen übereinstimmen, den Sie dort eingeben, da das Skript standardmäßig `web_unlocker` verwendet. Das Formular warnt, dass der Name dauerhaft ist:

![Das Bright Data Control Panel im Abschnitt Web Access, Breadcrumb Web Access dann Add API, bei Schritt 2 von vier: API-Typ wählen, API konfigurieren, Zahlungsmethode hinzufügen, API testen. Der API-Typ lautet Web Unlocker API, berechnet nur für erfolgreiche Anfragen. Ein erforderliches Namensfeld enthält web_unlocker_test über einem Hinweis, der lautet: 'Dieser Name kann später nicht geändert werden.' Ein Panel auf der rechten Seite zeigt den aktuellen Plan als Pay-as-you-go zu einem als CPM angegebenen Preis](https://media.brightdata.com/2026/09/BJ34D2IFGg.png)Die Zone in dieser Aufnahme heißt `web_unlocker_test`, also würde die Standardeinstellung des Skripts sie verfehlen. Setzen Sie entweder `BRIGHTDATA_ZONE` auf den Namen, den Sie eingegeben haben, oder verwenden Sie `web_unlocker` und lassen Sie den Standard in Ruhe. Der [Web Unlocker Quickstart](https://docs.brightdata.com/products/web-unlocker/quickstart) dokumentiert beides, und wir haben ohne Karte mit dem kostenlosen Kontingent begonnen, als wir das einrichteten. Die [Web Unlocker-Preisseite](/pricing/web-unlocker) listet das aktuelle kostenlose Kontingent und den Pay-as-you-go-Preis darüber auf, angegeben pro 1K erfolgreiche Anfragen. Das Panel schreibt diesen Preis als CPM.

Dieses Skript sendet die Anfrage durch den Web Unlocker-Endpunkt und parst das Ergebnis:

```none
import json
import os
import re
import requests

API_KEY = os.environ.get("BRIGHTDATA_API_KEY")
ZONE = os.environ.get("BRIGHTDATA_ZONE", "web_unlocker")
ENDPOINT = "https://api.brightdata.com/request"

LD_JSON = re.compile(
    r'<script[^>]*type\s*=\s*[\'"]application/ld\+json[\'"][^>]*>(.*?)</script\s*>',
    re.S | re.I,
)

def fetch_html(url, country="us"):
    """Return the rendered HTML for an Etsy URL, or raise on failure."""
    # Checked here rather than at import, so the browser path below runs
    # without an account.
    if not API_KEY:
        raise SystemExit("BRIGHTDATA_API_KEY is not set, see the exports above")
    response = requests.post(
        ENDPOINT,
        headers={"Authorization": f"Bearer {API_KEY}"},
        json={"zone": ZONE, "url": url, "format": "raw", "country": country},
        timeout=90,
    )
    response.raise_for_status()
    body = response.text
    # A quota error arrives as HTTP 200 with a short text body, and a block page
    # arrives as HTTP 200 of valid HTML. Neither contains ld+json, which is the
    # content this actually wants, so test for that rather than for either error.
    if not LD_JSON.search(body):
        raise RuntimeError(f"no ld+json in response, most likely blocked: {body[:200]!r}")
    return body

def product_jsonld(html):
    """Pick the Product block by @type. Every listing we opened had four."""
    for block in LD_JSON.findall(html):
        try:
            parsed = json.loads(block.strip())
        except json.JSONDecodeError:
            continue
        for node in parsed if isinstance(parsed, list) else [parsed]:
            if node.get("@type") == "Product":
                return node
    return None

def parse_listing(node):
    """Flatten a Product node, keeping the offer's range rather than its lowest price."""
    offer = node.get("offers", {})
    # schema.org allows a list of offers and a single priceSpecification object,
    # and Etsy serves both, so normalize before indexing into them.
    if isinstance(offer, list):
        offer = offer[0] if offer else {}
    specs = offer.get("priceSpecification", [])
    if isinstance(specs, dict):
        specs = [specs]
    base = next((s for s in specs if "priceType" not in s), {})
    was = next(
        (s for s in specs if "Strikethrough" in str(s.get("priceType", ""))), {}
    )
    # Not every listing carries a priceSpecification. Without this fallback a
    # single-variant listing records a null price and raises nothing.
    # A range arrives three ways: nested in priceSpecification, as AggregateOffer's
    # own lowPrice and highPrice, or not at all. Try them in that order.
    low = base.get("minPrice") or offer.get("lowPrice") or offer.get("price")
    high = base.get("maxPrice") or offer.get("highPrice") or offer.get("price")
    # availability is the only field that marks a dead listing, and JSON-LD lets it
    # arrive as a bare term, an array, or an @id object. Normalize before comparing.
    avail = offer.get("availability") or ""
    if isinstance(avail, list):
        avail = avail[0] if avail else ""
    if isinstance(avail, dict):
        avail = avail.get("@id", "")
    rating = node.get("aggregateRating", {})
    return {
        "sku": node.get("sku"),
        "title": node.get("name"),
        # Etsy serves a dead listing as a full HTTP 200 page that still
        # carries a price, so availability is the only field that says so.
        "availability": str(avail).rsplit("/", 1)[-1],
        "currency": offer.get("priceCurrency"),
        "price_min": low,
        # high can be a bundle maximum rather than the item's, where a listing
        # has an add-on axis. Count the axes before trusting it as a maximum.
        "price_max": high,
        "list_price": was.get("price"),
        # True only where the variations differ in price. Same-price variants
        # read false, so this is a price-spread test, not a variation test.
        "has_variations": None if low is None else low != high,
        "rating": rating.get("ratingValue"),
        "review_count": rating.get("reviewCount"),
        "shop": node.get("brand", {}).get("name"),
    }

if __name__ == "__main__":
    url = (
        "https://www.etsy.com/listing/753913297/"
        "smoky-quartz-ring-rose-gold-ring-women"
    )
    node = product_jsonld(fetch_html(url, country="us"))
    if node is None:
        raise SystemExit("no Product block on page: blocked, or the layout changed")
    print(json.dumps(parse_listing(node), indent=2))
```

Wir haben das Skript gegen ein Live-Listing ausgeführt, und es gab einen flachen Datensatz zurück. Der Preisbereich stammt von 1 Listing mit vielen separat bepreisten Variationen:

```none
{
  "sku": "753913297",
  "title": "Smoky Quartz Ring · Rose Gold Ring Women · Cocktail Rings · ...",
  "availability": "InStock",
  "currency": "USD",
  "price_min": "89.25",
  "price_max": "5613.75",
  "list_price": "119.00",
  "has_variations": true,
  "rating": "4.5",
  "review_count": 99,
  "shop": "AnemoneJewelry"
}
```

Über 3 Läufe gegen dasselbe Listing dauerten Fetches 23 bis 27 Sekunden und gaben zwischen 540 KB und 750 KB zurück. Diese Zahlen sind die Kosten des Entsperrschritts. Planen Sie für Latenz in diesem Bereich und nicht für das Sub-Sekunden-Timing eines Blocks.

Wenn Sie nur einige wenige Seiten benötigen und lieber kein Konto eröffnen möchten, erreicht ein lokaler Browser dasselbe Ergebnis mit etwa demselben Codeaufwand. Dieser Browser läuft von einer Adresse aus, die DataDome noch nicht abgelehnt hat. Er benötigt ein Display, also führen Sie ihn auf einem Server headed unter einem virtuellen Display wie Xvfb aus statt im headless-Modus. Installieren Sie Playwright und Chromium einmal:

```none
python3 -m venv .venv && source .venv/bin/activate   # skip if already active
pip install playwright requests
playwright install chromium
```

Dann tauschen Sie den Fetch aus und behalten dieselben 2 Parsing-Funktionen. Fügen Sie dies über dem `__main__`-Block ein, zusammen mit den anderen Funktionen:

```none
from playwright.sync_api import sync_playwright

def fetch_html_browser(url):
    """Fetch one page with a visible browser, since headless returns a 403."""
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False)
        context = browser.new_context(locale="en-US")
        page = context.new_page()
        page.goto(url, wait_until="domcontentloaded", timeout=45000)
        html = page.content()
        browser.close()
        # Same rule as the guard above: test for the content you want. A block
        # page is valid HTML, so only the missing ld+json shows it.
        if not LD_JSON.search(html):
            raise RuntimeError("no ld+json on page, most likely a block page")
        return html
```

Ändern Sie 1 Zeile im `__main__`-Block und sonst nichts:

```none
node = product_jsonld(fetch_html_browser(url))   # was: fetch_html(url, country="us")
```

Unser Lauf gab 535.247 Bytes zurück und wurde durch dieselben 2 Funktionen sauber geparst. Die Seite war auch in `INR` bepreist, weil ein Browser auf Ihrer Maschine von Ihrer eigenen Adresse ausgeht, und der Browser-Pfad nimmt kein `country`-Argument. Ohne dieses Argument können Sie das Exit-Land nicht festlegen, sodass dieser Pfad für einige wenige Seiten geeignet ist und nicht für einen Datensatz.

Der obige Code parst die Seite, anstatt sie an ein Modell zu senden. Etsy veröffentlicht die Felder als strukturierte Daten, sodass das Lesen deterministisch und praktisch kostenlos ist. Bei dem Listing, das wir gemessen haben, dauert die Auswahl des `Product`-Blocks und seine Vereinfachung einen Median von 0,3 Millisekunden.

Das Übergeben derselben Seite an ein Sprachmodell bedeutet dagegen 179.599 Tokens rohen HTMLs, das ist fast ein 200K-Token-Kontextfenster für 1 Produkt. Das Entfernen von Markup reduziert das auf 5.352 Tokens, eine Reduktion um 97 %. Dieses Verhältnis ist wichtiger als die Wahl des Modells.

Aber ein Parser, der aufhört zu matchen, gibt ein leeres Feld statt eines Fehlers zurück, während ein Modell zumindest etwas Falsches und Sichtbares produzieren würde. Nehmen Sie also den deterministischen Weg auf einer Site, die schema.org veröffentlicht. Nutzen Sie die gesparte Zeit, um zu überprüfen, ob der Parser noch die erwarteten Felder zurückgibt.

Shop-Seiten haben ebenfalls 4 dieser Blöcke, unter verschiedenen Typen, und einer davon zeigt, woher Listing-URLs kommen. `/shop/{shop_name}` gibt einen `Organization`-Knoten zurück, der den Shop beschreibt, und einen `ItemList`-Knoten, dessen `itemListElement` vollständige Listing-URLs enthält. `shop_itemlist` wählt die `ItemList` nach `@type` aus, sodass dieselbe Funktion mit `Organization` an ihrer Stelle die eigenen Felder des Shops zurückgibt. Bei dem Shop, den wir testeten, las `numberOfItems` 1.842, während eine einzelne Seite 36 URLs zurückgab, und `?page=2` gab 36 weitere ohne Überschneidungen zurück.

Der Enumerator nimmt einen Shop-Namen als Eingabe, also benötigen Sie eine Quelle für Shop-Namen, und 3 Quellen funktionieren, ohne den verbotenen Suchpfad zu berühren. Sie können Shops verwenden, die Sie bereits verfolgen, den oben genannten `findAllListingsActive`-Endpunkt oder einen vorbereiteten Datensatz. Dieser Endpunkt nimmt `keywords` mit einem Anwendungsschlüssel allein und enthält eine `shop_id` für jedes zurückgegebene Listing.

Wir haben Seiten über den Bereich und über das deklarierte Ende hinaus abgerufen:

```none
page  2    36 items
page 25    36 items
page 51    36 items
page 52     6 items      51 x 36 + 6 = 1,842
page 53    no ItemList block
page 60    no ItemList block
```

Die Gesamtzahl entspricht den 1.842, die der Shop deklariert. Über das Ende hinaus antwortet Etsy weiterhin mit einer vollständigen Seite von etwa 420 KB ohne `ItemList`.

Etsy gibt keinen Fehler und kein leeres Array zurück, auf das man warten könnte, sodass eine Schleife, die auf eines von beiden wartet, ewig gegen Seiten paginiert, die gut aussehen. Beenden Sie stattdessen beim fehlenden Block und lassen Sie die deklarierte Anzahl Ihre Arbeit überprüfen. Die [üblichen Muster für paginierte Sammlung](/blog/web-data/pagination-web-scraping) setzen eines dieser 2 Signale voraus, also gelten sie hier nicht.

Beide Funktionen gehören in dieselbe Datei wie die früheren Funktionen, da sie `LD_JSON` und `fetch_html` verwenden. Kommentieren Sie den Einstiegspunkt aus, den Sie nicht ausführen, da der Enumerator 20 Minuten dauert:

```none
def shop_itemlist(html):
    """Pick the ItemList block. The first block on a shop page is a video."""
    for block in LD_JSON.findall(html):
        try:
            parsed = json.loads(block.strip())
        except json.JSONDecodeError:
            continue
        for node in parsed if isinstance(parsed, list) else [parsed]:
            if node.get("@type") == "ItemList":
                return node
    return None

def enumerate_shop(shop_name, country="us"):
    """Page a shop until the ItemList stops appearing, and hand back the declared
    count so the caller can check it."""
    base = f"https://www.etsy.com/shop/{shop_name}"
    urls, declared, page = [], None, 1
    while True:
        suffix = "" if page == 1 else f"?page={page}"
        try:
            node = shop_itemlist(fetch_html(base + suffix, country=country))
            if node is None:
                break
            declared = node.get("numberOfItems", declared)
            urls += [item["item"]["url"] for item in node["itemListElement"]]
        except (RuntimeError, requests.RequestException, KeyError, TypeError,
            AttributeError) as err:
            print(f"stopped at page {page}: {err}", flush=True)
            break
        print(f"page {page}: {len(urls)} of {declared}", flush=True)
        # Breaking on the declared count here would make the comparison below
        # vacuous, so page until the ItemList block stops appearing.
        page += 1
    return urls, declared

if __name__ == "__main__":
    urls, declared = enumerate_shop("AnemoneJewelry")
    print(len(urls), "collected,", declared, "declared")
```

Der Enumerator macht 53 Fetches gegen die oben gemessenen Seiten, gibt 1.842 URLs zurück und überprüft die Gesamtzahl gegen die vom Shop deklarierte Anzahl. Vergleichen Sie diese 2 Zahlen bei jedem Lauf, da ein kurzer Lauf weniger URLs zurückgibt und keinen Fehler auslöst.

Das `try` muss sowohl den Parse als auch den Fetch abdecken. Eine 53-Anfragen-Schleife ist lang genug, um die Rate-Limit-Antwort zu erhalten, und ein einzelnes fehlerhaftes `itemListElement` verursacht denselben Schaden wie eine fehlgeschlagene Anfrage. Ohne den Guard löst eines von beiden bei Seite 30 einen Fehler aus und verwirft alle bisher gesammelten URLs. Das Abfangen beider führt stattdessen zu einem kurzen Lauf, und der Anzahlvergleich zeigt es. Das [Behandeln fehlgeschlagener Anfragen in Python](/blog/web-data/retry-failed-requests-python) folgt einem Standardmuster, und der einzige Etsy-spezifische Teil ist das Einbetten des Parse in den Guard.

Bei der oben gemessenen Latenz sind 53 Fetches 20 bis 24 Minuten und 53 Anfragen aus dem kostenlosen monatlichen Kontingent für 1 Shop. Führen Sie den Enumerator zuerst auf einem kleinen Shop aus und beobachten Sie die zunehmende Seitenanzahl, bevor Sie ihn auf einem Shop mit 1.842 Listings verwenden. Legen Sie auch ein Nutzungslimit auf der Zone fest, damit ein fehlgeschlagener Lauf bei einem Limit stoppt statt bei Ihrem Guthaben.

Wir haben dieselbe Entdeckung über den [Etsy-Shop-Endpunkt der Web Scraper API](/products/web-scraper/etsy/shop) als Batch-Job ausgeführt. Wir haben den Job auf dem Shop und nicht auf Listing-URLs ausgeführt und ihn auf 50 Datensätze für den Vergleich begrenzt. Er gab 50 Listings in 168,9 Sekunden zurück, also etwa 3,4 Sekunden pro Datensatz, ohne Duplikate und ohne locale-präfixierte URLs in diesem Lauf.

Das Sammeln dieses ganzen Shops dauert 53 Enumerations-Fetches plus 1.842 Listing-Fetches, also 1.895 Anfragen und etwa 13 Stunden single-threaded. Prüfen Sie diese 1.895 gegen das aktuelle kostenlose Kontingent, bevor Sie beginnen. Über dieses Kontingent hinaus wird dieselbe Arbeit zum Pay-as-you-go-Preis pro 1K erfolgreicher Anfragen abgerechnet.

Fixieren Sie `country` auch hier. Wir haben denselben Shop ohne es abgerufen und `/de/listing/`-URLs und deutsche Titel erhalten. Diese URLs würden als verschiedene Schlüssel für bereits unter ihrer `/listing/`-Form gespeicherte Elemente in einen Datensatz eingehen.

## Extraktionsprobleme, die einen Etsy-Datensatz unbemerkt beschädigen

Jedes Problem hier gibt HTTP 200 zurück und löst keine Exception aus. Von den 5 schreiben 4 eine plausible, aber falsche Zeile und die fünfte schreibt eine leere Zeile. Stattdessen findet man Monate später eine falsche Zahl. [Datenqualitätsmetriken](/blog/web-data/data-quality-metrics) erkennen diese Art von Fehler, nachdem die Daten gespeichert sind, und das Nicht-Schreiben der schlechten Zeile ist günstiger.

**Eine Listing-Seite hat 4 JSON-LD-Blöcke, nicht 1.** Etsy enthielt `Product`, `VideoObject`, `BreadcrumbList` und `FAQPage` in 4 separaten Script-Tags auf jedem Listing, das wir öffneten, alle mit dem `application/ld+json`-Typ. Die Seitenquelle zeigt sie in 4 aufeinanderfolgenden Zeilen:

![Vier aufeinanderfolgende Zeilen der Listing-Seitenquelle, nummeriert 144 bis 147, jede ein Script-Tag vom Typ application/ld+json. Ihre @type-Werte in der Reihenfolge sind Product, VideoObject, BreadcrumbList und FAQPage](https://media.brightdata.com/2026/09/H1Gvw2IKMl.png)Code, der `find()` aufruft und das erste Ergebnis nimmt, funktioniert auf Listing-Seiten und gibt auf Shop-Seiten unbemerkt den Video-Block zurück. Wählen Sie nach `@type` statt nach Position. Nichts anderes an der [Mechanik des Parsens von JSON in Python](/blog/how-tos/parse-json-data-with-python) ändert sich.

Eine Shop-Seite hat 4 eigene Blöcke in einer anderen Reihenfolge:

![Chromes Suchleiste auf der Shop-Seitenquelle mit der Aufschrift 'application/ld+json' und einem Zähler von 1 von 4, über den vier übereinstimmenden Script-Tags. Ihre @type-Werte in der Dokumentreihenfolge sind VideoObject, FAQPage, Organization und ItemList](https://media.brightdata.com/2026/09/B1lOv38Yfg.png)Bei dem Shop, den wir getestet haben, ist der erste Block ein Video und die gewünschte `ItemList` ist der letzte, sodass das Nehmen des ersten Ergebnisses fehlschlägt. Das Skript oben wählt stattdessen nach `@type` aus.

**Bei einem Listing mit Variationen ist `offers.price` der niedrigste Preis im Bereich, nicht der gesamte Bereich.** Bei dem Listing, das wir testeten, las `offers.price` `89.25`, während der in `offers` verschachtelte `priceSpecification`-Eintrag `minPrice` `89.25` und `maxPrice` `5613.75` deklarierte. Ein Parser, der `offers.price` liest, zeichnet die günstigste Variation auf und lässt den Bereich fallen. Das Speichern von `maxPrice` stattdessen ist auch keine Lösung, da `maxPrice` bei diesem Listing der Preis eines Bundles und nicht des Artikels allein ist.

Wir haben dieselbe URL mit aktivierten Variationen gesammelt und 61 separate Datensätze erhalten, 1 pro Variante, bepreist von 89.25 bis 1.871.25. Eine einzelne Listing-Zeile in Ihrer Tabelle repräsentiert 61 kaufbare SKUs über einen 21-fachen Preisbereich.

Ein zweites Dropdown auf der Seite multipliziert diesen Bereich:

![Das Dropdown 'Add Matching Jewelry' auf dem Listing geöffnet, zeigt vier Optionen, bepreist als Vielfache des Rings: 'No Thanks' $89.25 bis $1.871.25, entweder einzelnes passendes Stück $178.50 bis $3.742.50 und 'Full Set Earrings plus Pendant' $267.75 bis $5.613.75. Ein Metal Type-Dropdown sitzt darüber und der Überschriftspreis lautet $89.25 plus mit $119.00 durchgestrichen](https://media.brightdata.com/2026/09/ryhdPn8KGe.png)Diese 2 Maxima messen verschiedene Dinge, und dieses Listing hat 2 Variationsachsen. `Metal Type` reicht von 14k Gold Filled bei 89.25 bis zu den 3 Massivgold-Optionen bei 1.871.25. `Add Matching Jewelry (Optional)` multipliziert dann diesen Bereich. `No Thanks` läuft von 89.25 bis 1.871.25, entweder einzelnes passendes Stück von 178.50 bis 3.742.50 und `Full Set: Earrings + Pendant` von 267.75 bis 5.613.75.

Der deklarierte `maxPrice` ist der Massivgold-Ring plus beide passenden Stücke, 3 Artikel zu 1 Preis. Der Variations-Extract gab den Ring allein zurück und stimmte mit der `No Thanks`-Zeile auf den Cent genau überein.

Immer wenn ein Listing also eine Add-on-Achse hat, ist `maxPrice` das Maximum für ein Bundle und nicht für den Artikel. Eine darauf aufgebaute Preisreihe verfolgt stillschweigend Bundles. Zählen Sie die Variationsachsen, bevor Sie einen Bereich als den eigenen des Produkts speichern. Sie sind nicht im JSON-LD, also lesen Sie sie von der gerenderten Seite oder rufen Sie den Variations-Extract ab.

Dasselbe `priceSpecification`-Array enthält auch einen zweiten Eintrag, der als `StrikethroughPrice` markiert ist, sodass der Aktionspreis und der Listenpreis nebeneinander erscheinen, unterschieden nur durch eine schema.org-URL. Dieser Eintrag hat sein eigenes `minPrice` und `maxPrice`. Der `list_price`, den das Skript aufzeichnet, ist der niedrigste Preis im Listenpreisbereich, genau wie `offers.price` der niedrigste im aktuellen Bereich ist.

**Locale folgt der Exit-IP, und es ändert sich mehr als das Währungssymbol.** Wir haben 1 Listing 3 Mal in derselben Stunde abgerufen und dabei nur das Exit-Land geändert:

```none
country   currency   price    variation range      title
us        USD        89.25    89.25 - 5613.75      Smoky Quartz Ring, Rose Gold Ring Women
de        EUR        95.71    95.71 - 5058.76      Rauchquarzring, Damenring aus Roségold
gb        GBP        82.77    82.77 - 4338.22      Smoky Quartz Ring, Rose Gold Ring Women
```

Dasselbe Listing rendert von jedem Exit-Land unterschiedlich:

![Dasselbe Etsy-Listing von drei Exit-Ländern bepreist: Der US-Exit zeigt $89.25 mit $119.00 durchgestrichen, der deutsche Exit zeigt ab 95,88 EUR mit ab 127,84 EUR durchgestrichen, und der UK-Exit zeigt GBP 82.86 mit GBP 110.49 durchgestrichen und 25% Rabatt](https://media.brightdata.com/2026/09/SJDYD2LKGg.png)Diese Aufnahmen stammen von einem späteren Fetch als die 3 Zeilen, und nur die Dollar-Zahl blieb gleich. Die deutsche Seite schreibt auch ihren niedrigsten Preis als `ab`, und das `+` markiert dasselbe auf den anderen 2 Seiten.

Die 3 Fetches gaben dieselbe SKU, Bewertung und Bewertungsanzahl zurück, zu 3 verschiedenen Preisen in 3 Währungen. Das Verhältnis zwischen dem niedrigsten und höchsten Preis unterscheidet sich in den 3 Zeilen, 62,9-fach bei der US-Zeile gegen 52,9-fach und 52,4-fach, also bewegte sich zwischen diesen Fetches mehr als der Wechselkurs. Der deutsche Exit gab auch einen maschinell übersetzten Titel zurück, während die 2 englischen Locales den Original behielten.

Ein rotierender Pool, der Geografie ignoriert, erzeugt eine Preisreihe, die 3 Währungen mischt, und ein Textkorpus, der Sprachen mischt, und nichts in der Pipeline meldet ein Problem. Fixieren Sie das Exit-Land pro Sammlungslauf und speichern Sie die Währung neben jedem Preis.

Dasselbe Problem tritt in vorbereiteten Daten auf. Das von uns heruntergeladene 1.000-Datensatz-Sample enthielt 19 Währungen, mit 109 Zeilen in einer anderen Währung als USD, davon 14 in vietnamesischem Dong. Dieses Sample aktualisiert sich, also wird Ihre Kopie von diesen Gesamtzahlen abweichen. Führen Sie denselben Vergleich mit Ihrer eigenen Kopie durch.

Das Mitteln der Preisspalte ohne Lesen der Währungsspalte bläht den Mittelwert auf:

```none
mean(final_price), all rows          31,238.84   n=991
mean(final_price), currency = USD       137.57   n=882
                                        ~227x
median(final_price), all rows            26.00
```

In dieser Spalte tragen 14 von 991 Zeilen 87% der Gesamtsumme bei, aber 109 Zeilen sind Nicht-USD und alle müssen behandelt werden. Die Abfrage läuft, die Spalte ist ein sauberer Float, und die Antwort ist um 2 Größenordnungen falsch. Der Median bewegt sich kaum, da die Nicht-USD-Zeilen nur einen kleinen Anteil der Spalte ausmachen. Ein Mittelwert und ein Median, die so stark voneinander abweichen, zeigen nur, dass ein schwerer Schwanz vorhanden ist. Das Gruppieren nach der Währungsspalte trennt gemischte Einheiten von gewöhnlicher Schiefe.

Ein arXiv-Papier vom März 2026 über Marketplace-Listings, das weiter unten erneut zitiert wird, beschränkte sein Sample auf Listings in USD, bevor es Analysen durchführte. Das löst das Problem nach der Erfassung und nicht während ihr. Das Filtern auf diese Weise ändert auch die Population, die der Durchschnitt beschreibt, da es Listings in anderen Währungen herausfiltert statt sie umzurechnen.

Dieses Problem ist auf dem Agent-Pfad am schwierigsten zu erkennen. Wir haben dieses Listing über einen MCP-Server abgerufen, dessen Schema nur eine URL akzeptiert, und den tschechischen Storefront in CZK erhalten. Der auf ein Land fixierte REST-Aufruf meldet dasselbe Listing zu 89.25 USD.

Die Ursache ist die Schnittstelle des Tools, nicht der Fetch. Ohne Land- oder Locale-Parameter zum Setzen nehmen Sie, welchen Exit der Server gerade verwendet. Prüfen Sie dieses Verhalten bei jedem solchen Server, bevor Sie ihn mit einem Agent verbinden, da der Exit die Währung jeder nachgelagerten Antwort bestimmt.

Also sammeln Sie Etsy-Daten in Ihrem eigenen Speicher auf einem fixierten Locale, und lassen Sie den Agent diesen Speicher lesen statt live pro Frage zu fetchen. Ein Agent, der jedes Mal stillschweigend in einer anderen Währung antwortet, ist schlechter als ein Agent, der nicht antworten kann.

**Ein totes Listing ist eine vollständige Seite mit einem Preis darauf.** Etsy gibt keinen 404-Fehler für ein abgelaufenes oder ausverkauftes Listing zurück. Wir haben ein Listing aus dem Jahr 2007 abgerufen und HTTP 200, 465.563 Bytes, einen vollständigen `Product`-Block und `price` `13.00` `USD` erhalten.

Die Seite rendert vollständig und zeigt sowohl das Ausverkauft-Banner als auch den Preis:

![Eine Etsy-Listing-Seite. Ein Banner oben lautet 'This item is sold out.' Direkt daneben zeigt die Seite weiterhin einen Preis von $13.00, zusammen mit den Produktfotos, dem Verkäufernamen und den Artikeldetails, genau wie ein Live-Listing](https://media.brightdata.com/2026/09/Byv5vh8tzl.png)`offers.availability` ist das einzige Feld, das dem Preis widerspricht, und es lautet `schema.org/OutOfStock`. Ein Parser, der es überspringt, zeichnet einen toten Artikel zum vollen Preis auf, also liest das Skript oben dieses Feld.

Dieses Feld ist in vorbereiteten Daten weniger zuverlässig als auf der Seite. In derselben Kopie waren 74 von 1.000 Zeilen ausverkaufte Listings, `availability` war bei allen 74 leer, und 65 zeigten noch einen numerischen Preis. Das Zeichen dort ist ein `show_sold_out_detail`-Parameter in der gespeicherten URL. Nur die Zeilen zu behalten, deren `availability` `InStock` lautet, würde 798 Live-Zeilen verwerfen, da das Feld auch bei den meisten von ihnen fehlt.

**Eine 2xx-Antwort bedeutet nicht, dass Sie Daten haben.** Dieses Problem liegt in der Collection-Schicht statt in der Payload, und wir haben es mit dem Skript oben während des Testens gesehen. Der Entsperr-Endpunkt erklärt sich im Body. Als das Konto ein Anfrage-Rate-Limit erreichte, antwortete es mit `200` und einem 111-Byte-Klartext-Body mit dem Inhalt `Your system is sending too many of this type of request`. Die Statuszeile bleibt ein Erfolg, also passiert `raise_for_status()`, der Parser findet keinen `Product`-Block, und eine Schleife schreibt leere Zeilen ohne eine einzige Exception.

Die Web Scraper API behandelt denselben Fall by Design. Ihr synchroner Collect-Endpunkt gibt Datensätze innerhalb von 1 Minute zurück, und längere Jobs laufen asynchron weiter. Derselbe Endpunkt antwortet mit `202` und einer `snapshot_id` sowie einem `retry-after`, wenn ein Job über diese Minute hinausgeht, sodass Sie das Ergebnis abrufen können, sobald es fertig ist, wie die [API-Referenz](https://docs.brightdata.com/api-reference/scrapers/synchronous-requests) dokumentiert. Beide Antworten sind Erfolgs-Statuscodes, also verzweigen Sie vor dem Indexieren in eine Datensatzliste auf den Statuscode.

Der Guard in `fetch_html` ist 2 Zeilen und testet auf eine Seite mit ld+json statt auf einen der beiden Fehler. Das Ausführen des Enumerators gegen einen Live-Shop fand einen dritten Fall, einen `200` mit leerem Body, und derselbe Guard fing ihn ohne jede Änderung ab. Testen Sie also die Antwort auf den gewünschten Inhalt statt gegen die bereits gesehenen Fehler, da Anbieter-Fehlertext keine stabile Schnittstelle ist. Schreiben Sie das Äquivalent für jede Fetch-Schicht, die Sie verwenden, denn ein Erfolgs-Statuscode garantiert keine Payload.

Ein gearbeitetes Beispiel beweist, dass ein Problem existiert, nicht dass es häufig ist. Wir haben die Preis-Bereich- und Durchstreichungsprobleme gegen 100 Listings aus beiden Entdeckungspfaden geprüft. Variationen sind bei 98 von 100 vorhanden, und `initial_price` unterscheidet sich bei denselben 98 von `final_price`. Keines der beiden Probleme ist ein Randfall, den man aufschieben kann. Diese 100 kamen über die 2 oben genannten Entdeckungspfade und nicht als Zufallsstichprobe aus Etsys Kategorien. Lesen Sie also 98 als Minimum für Schmuck-Listings statt als Rate für die gesamte Site.

Dieselbe Prüfung zeigt, dass das oben verwendete Listing in einer Hinsicht ungewöhnlich ist. Dieses Listing hat 99 Bewertungen, während der Median in diesem Crawl 1 und im veröffentlichten Datensatz-Sample 0 ist.

## Wann man einen verwalteten Datensatz kauft statt einen Scraper zu pflegen

Sie können den Scraper aufbauen, und der obige Code ist der größte Teil davon. Die Entscheidung ist, welche Fehler Sie selbst behandeln möchten.

Wir haben dasselbe Listing erneut durch die [Web Scraper API](/products/web-scraper/etsy) geführt, diesmal nach URL statt nach Shop. Sie gab 58 Felder zurück, gegenüber den 14 im rohen `Product`-Block, und die zusätzlichen Felder behandeln die meisten der oben genannten Probleme:

```none
raw JSON-LD (geo=us)          Web Scraper API
-----------------------------------------------------
price 89.25 (range minimum)   final_price 89.25
119.00 (StrikethroughPrice)   initial_price 119
not present                   discount_percentage 25
not present                   listing_has_variations true
not present                   reviews_count_shop 15129
not present                   is_star_seller false
4 embedded reviews            6 top_reviews
14 fields                     58 fields
```

Sie konfigurieren diesen Extraktor pro Eingabe-URL und setzen `all_variations` auf true für das Preis-Bereich-Problem:

![Die Bright Data Scraper-Bibliothek auf dem etsy.com-Scraper, überschrieben POST Etsy - collect by URL zu einem Preis pro tausend Datensätze. Eine Endpunktliste bietet collect by URL, discover by keywords und discover by shop url. Die Eingabetabelle enthält eine Zeile: eine Listing-URL mit all_variations auf true gesetzt. Eine Scraper-Modusauswahl bietet synchron, ausgewählt, oder asynchron. Ein Code-Panel zeigt die generierte authentifizierte Anfrage, die api.brightdata.com/datasets/v3/scrape aufruft](https://media.brightdata.com/2026/09/By2iP38tGl.png)Die 6 Felder, die wir über beide Pfade verglichen, stimmten exakt überein, und zwar Währung, berechneter Preis, Listenpreis, Bewertung, Artikel-Bewertungsanzahl und Versandursprung. Führen Sie diese Prüfung durch, bevor Sie einem der beiden Pfade vertrauen.

**Der Zeitvergleich kehrt sich um, und der Modus entscheidet, wie stark.** Über den synchronen Endpunkt dauerte die strukturierte Extraktion etwa 50 Sekunden für einen einzelnen Datensatz, gegenüber 27 Sekunden für den rohen Fetch. Er rendert und normalisiert statt Bytes zurückzugeben. Die 50 Sekunden lassen etwa 10 Sekunden innerhalb des obigen 1-Minuten-Timeouts. Der Endpunkt ist für 1 URL und eine sofortige Antwort ausgelegt.

Wir haben denselben Scraper stattdessen als Batch-Job ausgeführt und die obigen 50 Datensätze zu 3,4 Sekunden pro Datensatz erhalten. Jeder Datensatz kostet etwa 1/8 der 27 Sekunden, die ein roher Fetch dauert. Im Batch-Modus ist der `202` die erwartete Antwort und kein zu behandelnder Fehler.

Für einen wiederkehrenden Crawl entfernt der strukturierte Pfad Selektor-Wartung, Locale-Fixierung und Preis-Bereich-Behandlung von Ihrem Team für die zurückgegebenen Felder. Für 1 Listing ist es in jedem Modus langsamer. Der obige Diff zeigt die Preisbehandlung gelöst, und der 50-Datensatz-Lauf zeigte keine locale-präfixierten URLs. Selektor-Wartung ist der einzige Teil, den kein einzelner Lauf testen kann. Der strukturierte Pfad wird auf dieselbe Weise wie Web Unlocker abgerechnet, mit dem aktuellen kostenlosen Kontingent und dem Per-1K-Datensatz-Preis auf der [Web Scraper API-Preisseite](/pricing/web-scraper).

**Das gleiche Sample enthält 2 Arten von Datensatz statt 1, also planen Sie für beide auf der Kaufseite.** Von den 1.000 Zeilen haben 128 den vollständigen Feldsatz, und die anderen 872 lassen 12 seiner Felder leer, einschließlich `description`, `product_category` und `store_country`.

Die Aufteilung verfolgt das Listing-Alter, mit dem vollständigen Datensatz bei Artikeln, die ab Ende 2025 gelistet wurden. Ein Bulk-Extract über Jahre mischt daher beide Arten in 1 Datei. Dieses Verhältnis sollte sich zum vollständigen Datensatz hin verschieben, wenn das Korpus altert. Prüfen Sie die Feldabdeckung gegen Ihre eigenen erforderlichen Spalten, bevor Sie die Bestellgröße festlegen, nicht danach.

**Das Bewertungsvolumen benötigt dieselbe Prüfung, bevor Sie bestellen.** In der von uns abgerufenen Kopie hatten 753 von 1.000 Listings keine Bewertungen, also ist der Median null. Die Top 10% der Listings haben 98% aller Bewertungen. Der Mittelwert von 52,5 pro Listing beschreibt die Datei als Ganzes und kein Listing, das Sie öffnen werden.

Die Bewertungsschiefe sieht aus wie der Währungsfall, ist aber ein anderer Fehler mit einer anderen Lösung. Der Währungsfall oben ist ein Einheitenfehler, und der Mittelwert ist falsch. Bewertungsvolumen ist Schiefe, und dort ist der Mittelwert für eine Gesamtsumme richtig. Eine Zufallsstichprobe von 1.000 Listings sollte etwa 52.500 Bewertungen zurückgeben, also verwenden Sie den Mittelwert, wenn Sie ein Bulk-Korpus planen. Bei einer Stichprobe in Pilot-Größe macht diese Konzentration die Schätzung unzuverlässig.

Abdeckung ist eine andere Frage. Mit 753 von 1.000 bei null haben nur etwa 25% der von Ihnen gekauften Zeilen Bewertungen.

Wenn die benötigten Daten historisch statt live sind, überspringt ein vorbereiteter Datensatz den Crawl. Die [Etsy-Datensatz](/products/datasets/etsy)-Seite listet die aktuelle Feldanzahl, Gesamtdatensätze, den Pro-Datensatz-Preis und die Mindestbestellung auf, und diese 4 Zahlen sind die Kaufseiten-Arithmetik.

Die Pro-Datensatz-Zahl auf dieser Seite ist der Einmalpreis, und Aktualisierungspläne von halbjährlich bis täglich kommen als Abonnements, die ihn rabattieren. Wie aktuell die Daten sind, spielt ebenfalls eine Rolle. Die Seite beschreibt vorgesammelte Datensätze als Tage bis Monate alt, während die Erfassung auf Anfrage es Ihnen ermöglicht, dieses Limit vor dem Checkout festzulegen. Sie wählen den Aktualisierungsplan und das Volumen-Level direkt auf der Datensatz-Seite.

Diese Zahlen ändern sich ohne Ankündigung, also lesen Sie sie von der Seite, bevor Sie budgetieren, und behandeln Sie die 2 Preisseiten genauso. Die Datensatz-Seite zeigt ein Sample der Datensätze unter der Zusammenfassungszeile, bis Sie Zugang beantragen unscharf:

![Die Bright Data Etsy-Datensatz-Seite. Eine Zusammenfassungszeile enthält die Datenfeld-Anzahl, die Gesamtdatensätze, den Startpreis pro Datensatz und die Mindestbestellung. Darüber befinden sich die Etsy-Datensatz-Überschrift, eine Beschreibung der Attribute des Datensatzes und Schaltflächen zum Kontaktieren des Vertriebs oder Kaufen des Datensatzes](https://media.brightdata.com/2026/09/S1FnvnUKfg.png)Ein externer Referenzpunkt ist hier mehr wert als eine Anbieter-Behauptung. Dasselbe Papier, [Mecha-nudges for Machines](https://arxiv.org/abs/2603.23433), dokumentiert in Anhang B, woher seine Daten stammen. Die Autoren geben an, dass die Rohdaten “von dem Unternehmen Bright Data erhalten wurden, das strukturierte Datensätze von Etsy-Produktlistings bereitstellt”. Ihr Extract “wurde am 12. November 2025 gesammelt und am selben Tag geliefert”. Sie beschreiben 2 Snapshots mit 5 Millionen und 1,06 Millionen Listings. Dieser Anhang ist überprüfbar, und eine Anbieter-Fallstudie ist es nicht.

Die Regel hier ist eng. Bauen Sie den Scraper, wenn Sie einige tausend Listings benötigen, die Sie per URL aufzählen können, und Sie 1 Locale fixieren können. Kaufen Sie die Collection-Schicht, wenn die Liste der URLs das Schwierige ist oder wenn der Crawl weiterlaufen muss. Kaufen Sie auch, wenn der Datensatz Preisarbeit speist, da die Preis-Bereich- und Durchstreichungsfelder bereits getrennt ankommen. Die Währungsspalte muss auf beiden Pfaden noch gefiltert werden.

Bei dem oben gemessenen Shop kostet der Aufbau 1.895 Anfragen und etwa 13 Stunden single-threaded für 1.842 Listings. Die Kaufseite ist eine Mindestbestellung vorbereiteter Datensätze. Diese 2 Zahlen sind nicht direkt vergleichbar, da die Aufbaukosten pro Shop anfallen und die Kaufkosten ein Minimum sind, das Sie auf Shops verteilen.

## Abschließende Gedanken

Etsy blockiert gewöhnliches Fetching, während es schema.org JSON-LD auf denselben öffentlichen Seiten veröffentlicht, sodass Extraktion eine kurze Aufgabe ist und Zugang das meiste der Arbeit ist. Der Transport entscheidet nicht über den Zugang, da ein headed Browser eine Seite lud, die 9 abgestimmte HTTP-Clients nicht laden konnten, und Etsy denselben Browser bei seiner zweiten Anfrage ablehnte. Das Engineering-Problem ist also, wie man das Sammeln fortsetzt, nicht wie man wie ein Browser aussieht. Welchen Weg Sie auch nehmen, die Datenfehler kosten mehr als die Zugangs-Fehler, da eine gemischte Währungsspalte oder ein totes Listing zum vollen Preis sauber parst und man es Monate später findet. Holen Sie 1 Listing durch einen rohen Fetch und einen strukturierten Extraktor, vergleichen Sie die Felder, und lassen Sie das Ergebnis [Aufbauen versus Kaufen](https://docs.brightdata.com/concepts/web-scraper-api-vs-diy) entscheiden, bevor Sie den Crawler schreiben.

## Häufig gestellte Fragen

### Gibt es eine API für Etsy?

Ja. Die Etsy Open API v3 listete 76 Pfade, als wir zählten, von denen 31 GET-Operationen nur einen Anwendungsschlüssel benötigen. Sie gibt Listings, Shops, Bewertungen und Taxonomie zurück. Für Shops, die Sie nicht betreiben, lässt sie Verkäufe pro Listing, Keyword-Suchvolumen, Konversionsrate und Historie weg, die viele Datenprojekte benötigen.

### Ist die Etsy-API kostenlos?

Die API selbst hat keinen veröffentlichten Preis, aber der Zugang hängt von der Genehmigung und von Rate-Limits ab, die pro Anwendungsschlüssel festgelegt werden. Etsy entscheidet, wer höhere Limits bekommt, und kann zusätzliche Bedingungen oder Gebühren anhängen. Die praktischen Kosten sind das Rate-Limit und keine Gebühr.

### Warum wird mein Etsy-Scraper blockiert?

Etsy betreibt DataDome, das einen 403 mit einer kurzen Blockseite und einem `X-DataDome-riskscore`-Header zurückgibt, der Ihre Anfrage bewertet, wobei 1,0 der schlechteste Wert ist. Der Score folgt Ihrer aufrufenden IP und der Anfrage-Signatur. In unseren Tests senkten Header-Bearbeitungen den Score, und Chrome TLS-Impersonation erhöhte ihn, und keines von beidem gab eine Seite zurück.

### Erlaubt Etsy Web-Scraping?

Nicht ohne ausdrückliche Genehmigung von Etsy. Die Nutzungsbedingungen sind das strengere Dokument. robots.txt verbietet die Keyword-Suche, die Verkaufshistorie und Favoriten in jeder Locale-Variante und lässt Listing- und Shop-Seiten offen. Etsy schreibt diese Datei ohne Ankündigung neu, also lesen Sie die Live-Kopie, bevor Sie aufbauen.

### Kann man Etsy mit Python scrapen?

Ja. Listing-Seiten betten schema.org JSON-LD ein, sodass die Extraktion keine CSS-Selektoren benötigt. Wählen Sie den `application/ld+json`-Block, dessen `@type` `Product` ist, und vereinfachen Sie dann das Angebots-Objekt. Der Fetch ist die schwierige Hälfte, und das Sammeln im Volumen benötigt neue Browsing-Kontexte und rotierende Adressen.

### Wie bekomme ich Etsy-Verkaufsdaten?

Verkäufe sind nur auf Shop-Ebene öffentlich. Der `getShop`-Endpunkt gibt `transaction_sold_count` zurück, eine Lifetime-Zahl für den gesamten Shop. Nichts teilt das pro Listing für einen Shop auf, den Sie nicht betreiben, also kommen die Pro-Listing-Zahlen eines Tools von woanders. Behandeln Sie diese als Schätzungen und prüfen Sie sie gegen Shop-Gesamtzahlen.

### Hat Etsy eine Sitemap zum Crawlen?

Keine bei unserer letzten Prüfung. Die robots.txt-Datei deklariert null `Sitemap:`-Direktiven, und `/sitemaps.xml` gibt einen 403 mit leerem Body zurück. Ohne Sitemap müssen Sie URLs von Shop-Seiten, dem API-Endpunkt `findAllListingsActive` oder einem vorbereiteten Datensatz entdecken. Keines dieser 3 berührt den verbotenen Suchpfad.

### Blockiert Etsy KI-Crawler wie GPTBot?

Nicht namentlich, als wir prüften. Die robots.txt-Datei deklariert nur 3 User-Agent-Gruppen, keine davon ein KI-Crawler, und Etsy veröffentlicht weder `llms.txt` noch `ai.txt`. DataDome lehnte GPTBot und ClaudeBot trotzdem ab, beide mit einem schlechteren Score von 0,9814 als die 0,923, die ein Chrome User-Agent erzielte. Sinnlose Strings erzielten denselben Score.



Vertrieb kontaktierenGratis testen![google social icon](/wp-content/themes/brightdata/assets/images/ic_google.svg)









 Inhaltsverzeichnis







Dedicated Scraper APIs &amp; No-Code Scrapers

Over 1000 scrapers for all popular domains. Simplify your web scraping.

[See pricing](/pricing/web-scraper "See pricing")

Just want data? Skip scraping.

Hundreds of ready-to-use datasets from all popular domains.

[See pricing](/pricing/datasets "See pricing")







 [ ](https://news.ycombinator.com/submitlink?t=Etsy+scrapen%3A+Leitfaden+2026&u=https://brightdata.de/blog/web-data-de/how-to-scrape-etsy) [ ](https://www.linkedin.com/shareArticle?mini=true&title=Etsy+scrapen%3A+Leitfaden+2026&url=https://brightdata.de/blog/web-data-de/how-to-scrape-etsy) [ ](http://www.reddit.com/submit?title=Etsy+scrapen%3A+Leitfaden+2026&url=https://brightdata.de/blog/web-data-de/how-to-scrape-etsy)







##  Das könnte Sie auch interessieren

 [ ![Web Scraping with GLM](https://media.brightdata.de/2026/09/Web-Scraping-with-GLM.png) ](https://brightdata.de/blog/ai/web-scraping-with-glm "Web-Scraping mit GLM: Text- und visuelle Datenextraktion")

 [AI



 ![Antonello Zanini](https://media.brightdata.de/2022/12/Antonello-Zanini-2-50x50.jpg)

Antonello Zanini

Technical Writer





### Web-Scraping mit GLM: Text- und visuelle Datenextraktion

Verwenden Sie GLM-5.3 mit Bright Datas Web Unlocker für KI-gestütztes Web-Scraping. Extrahieren Sie automatisch Text- und visuelle Daten und umgehen Sie gängige Hindernisse.



 16-Sep-2026

 5 min lesen

 ](https://brightdata.de/blog/ai/web-scraping-with-glm)

 [ ![Containers as a Service (CaaS)](https://media.brightdata.de/2026/09/Container-as-a-Service.png) ](https://brightdata.de/blog/web-data-de/containers-as-a-service "Containers as a Service (CaaS): So nutzen Sie es für Web-Datenpipelines und KI-Agenten")

 [Web Data



 ![Antonello Zanini](https://media.brightdata.de/2022/12/Antonello-Zanini-2-50x50.jpg)

Antonello Zanini

Technical Writer





### Containers as a Service (CaaS): So nutzen Sie es für Web-Datenpipelines und KI-Agenten

Wie Containers as a Service funktioniert und wie eine Bright Data Web-Scraping-Pipeline für KI-Agenten containerübergreifend skaliert wird.



 16-Sep-2026

 13 min lesen

 ](https://brightdata.de/blog/web-data-de/containers-as-a-service)

 [ ![Cursor + Bright Data vs a default coding agent setup](https://media.brightdata.de/2026/09/Cursor-Bright-Data-vs-a-default-coding-agent-setup.png) ](https://brightdata.de/blog/ai/cursor-bright-data-vs-default-coding-agent "Cursor + Bright Data vs. ein Standard-Coding-Agent-Setup: Aufbau eines echten Preis-Trackers")

 [AI



 ![Satyam Tripathi](https://media.brightdata.de/2024/09/Satyam-Tripathi-50x50.png)

Satyam Tripathi

Technical Writer





### Cursor + Bright Data vs. ein Standard-Coding-Agent-Setup: Aufbau eines echten Preis-Trackers

Eine Preis-Tracker-Aufgabe, 41 eingefrorene Retailer-Seiten, zwei Coding-Agents, gleicher Prompt und gleiches Modell. Mit Bright Data’s MCP darunter: 89% Feldgenauigkeit und 40 von 41 gelesenen Seiten. Ohne: 72% und 34.



 16-Sep-2026

 27 min lesen

 ](https://brightdata.de/blog/ai/cursor-bright-data-vs-default-coding-agent)
