Dlaczego warto scrapować Etsy — i dlaczego to trudniejsze niż się wydaje
Etsy to jedna z najbogatszych baz danych o niszach produktowych w internecie. Ponad 7 milionów sprzedawców, miliony aktywnych listingów i publiczne dane o sprzedaży, cenach i recenzjach — wszystko to kopalnia wiedzy dla zespołów print-on-demand (POD) i narzędzi do badania rynku. Ale scrapowanie Etsy nie jest proste. Strona chroni się przed botami za pomocą Cloudflare, wewnętrznych limitów żądań i śledzenia sesji.
W tym przewodniku pokażę Ci:
- Jak jest zbudowane Etsy — od wyszukiwania po strony sklepów
- Jakie technologie anti-bot stosuje i jak je omijać
- Konkretne wzorce scrapowania do odkrywania nisz (trending, seller count, avg price)
- Pełny przykład w Python — od wyszukiwania po detale listingów z rotacją IP
- Analitykę sklepów — listingi, sprzedaż, recenzje
- Etykę — dlaczego scrapowanie dla badań to nie kopiowanie designów
Ważne: Ten przewodnik jest przeznaczony do badań rynkowych i analizy trendów. Nie służy do kopiowania czyichś prac ani naruszania praw autorskich.
Struktura Etsy — co i jak scrapować
Zanim zaczniesz pisać kod, musisz zrozumieć, jak Etsy organizuje dane. To nie jest płaska strona — to złożony marketplace z kilkoma kluczowymi typami stron.
Strona wyszukiwania
URL: https://www.etsy.com/search?q=QUERY
Wyniki wyszukiwania to główny punkt wejścia. Każda strona zwraca do 48 listingów (tzw. listing cards). Parametry URL pozwalają filtrować:
min_price/max_price— zakres cenowyship_to— kraj dostawylocationQuery— lokalizacja sprzedawcyitem_type— typ przedmiotu (handmade, vintage, supplies)
Selektory CSS listing card na stronie wyszukiwania:
- Kontener karty:
div.v2-listing-card - Tytuł:
h3.v2-listing-card__info__title - Cena:
span.currency-value - Link do listingu:
a.listing-link(atrybuthref) - URL obrazu:
img.wt-width-full(atrybutsrclubdata-src-img)
Strona listingu (detail page)
URL: https://www.etsy.com/listing/LISTING_ID/SLUG
To strona konkretnego produktu. Znajdziesz tu:
- Pełny opis produktu
- Cenę i opcje wariantów
- Liczbu sprzedanych sztuk (
"X people have this in their cart") - Recenzje z ocenami
- Nazwa sklepu i link do profilu
Strona sklepu
URL: https://www.etsy.com/shop/SHOP_NAME
Profil sklepu ujawnia:
- Liczba sprzedaży — badge
"X Sales"(Etsy pokazuje przybliżoną wartość) - Liczba listingów
- Oceny i recenzje
- Rok dołączenia
- Lokalizację
Drzewo kategorii
Etsy organizuje produkty w hierarchię kategorii:
https://www.etsy.com/c/jewelry→ biżuteriahttps://www.etsy.com/c/clothing→ odzieżhttps://www.etsy.com/c/home-and-living→ dom i ogród
Każda kategoria ma podkategorie. Możesz rekursywnie przechodzić drzewo, wyciągając linki z nawigacji boczej (nav.category-nav).
Anti-bot Etsy — Cloudflare i limity żądań
Etsy korzysta z Cloudflare jako pierwszej linii obrony. Oznacza to:
- Wyzwanie JS — pierwsze żądanie z nowego IP często trafia na stronę challenge'ową Cloudflare
- Rate limiting — z jednego IP możesz wysłać około 60–80 żądań na minutę, zanim dostaniesz 429
- Session tracking — cookies i fingerprinting przeglądarki; nagłe zmiany zachowania flagują sesję
- Canvas/WebGL fingerprinting — zaawansowane wykrywanie headless browserów
Jakie proxy do Etsy?
Dla Etsy residential proxy to praktycznie wymóg. Datacenter IP są masowo blokowane przez Cloudflare. Mobile proxy działają świetnie (wyższy trust score), ale są droższe.
| Typ proxy | Trust score przy Cloudflare | Sukces scrapowania Etsy | Koszt | Zalecenie |
|---|---|---|---|---|
| Datacenter | Niski | 10–30% (częste CAPTCHA) | Niski | Tylko do testów |
| Residential | Wysoki | 85–95% | Średni | Zalecane do Etsy |
| Mobile | Bardzo wysoki | 95%+ | Wysoki | Dla dużych wolumenów |
Rotacja IP na każde żądanie (per-request rotation) jest kluczowa przy masowym scrapowaniu wyszukiwania. Do pobierania detail pages używaj sticky sessions — jedno IP na całą sesję przeglądania sklepu.
Wzorce scrapowania do odkrywania nisz
Dla zespołów POD i badaczy rynku, Etsy to złota kopalnia danych o niszach. Oto konkretne wzorce:
1. Trending search terms — popularne zapytania
Etsy nie ma publicznego API do trending terms, ale możesz wyciągnąć sugestie z autouzupełniania:
import requests
from urllib.parse import quote
def get_etsy_suggestions(keyword, proxy_url):
url = f"https://www.etsy.com/api/v3/ajax/member/search-suggestions?query={quote(keyword)}"
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}
resp = requests.get(url, headers=headers, proxies={"http": proxy_url, "https": proxy_url})
return resp.json() # zwraca listę sugestii
proxy = "http://user-country-US:pass@gate.proxyhat.com:8080"
print(get_etsy_suggestions("mug", proxy))
Wysyłaj zapytania dla różnych seed keywords i buduj mapę trendów. Powtarzaj codziennie, żeby wyłapać trendy sezonowe.
2. Seller count per niche — ile sklepów sprzedaje w danej niszy
Scrapuj stronę wyszukiwania dla słowa kluczowego i licz unikalne nazwy sklepów:
import requests
from bs4 import BeautifulSoup
from urllib.parse import quote
def count_sellers_for_niche(keyword, pages=3, proxy_url=None):
unique_shops = set()
proxies = {"http": proxy_url, "https": proxy_url} if proxy_url else None
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}
for page in range(1, pages + 1):
url = f"https://www.etsy.com/search?q={quote(keyword)}&page={page}"
resp = requests.get(url, headers=headers, proxies=proxies, timeout=30)
soup = BeautifulSoup(resp.text, "html.parser")
cards = soup.select("div.v2-listing-card")
for card in cards:
shop_el = card.select_one("span.v2-listing-card__shop-name")
if shop_el:
unique_shops.add(shop_el.get_text(strip=True))
return {"keyword": keyword, "unique_shops": len(unique_shops), "shops": list(unique_shops)}
proxy = "http://user-country-US:pass@gate.proxyhat.com:8080"
result = count_sellers_for_niche("funny coffee mug", pages=5, proxy_url=proxy)
print(result)
3. Average price points — średnia cena w niszy
Wyciągnij ceny ze strony wyszukiwania i policz średnią, medianę i rozkład:
import re
import statistics
def extract_prices(keyword, pages=3, proxy_url=None):
prices = []
proxies = {"http": proxy_url, "https": proxy_url} if proxy_url else None
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}
for page in range(1, pages + 1):
url = f"https://www.etsy.com/search?q={quote(keyword)}&page={page}"
resp = requests.get(url, headers=headers, proxies=proxies, timeout=30)
soup = BeautifulSoup(resp.text, "html.parser")
cards = soup.select("div.v2-listing-card")
for card in cards:
price_el = card.select_one("span.currency-value")
if price_el:
price_text = price_el.get_text(strip=True)
match = re.search(r'[\d.,]+', price_text)
if match:
price = float(match.group().replace(',', '.'))
prices.append(price)
if not prices:
return None
return {
"keyword": keyword,
"count": len(prices),
"avg": round(statistics.mean(prices), 2),
"median": round(statistics.median(prices), 2),
"min": min(prices),
"max": max(prices),
}
proxy = "http://user-country-US:pass@gate.proxyhat.com:8080"
print(extract_prices("custom pet portrait", pages=5, proxy_url=proxy))
Pełny przykład — od wyszukiwania po detale listingów
Poniższy skrypt łączy wszystko w jeden pipeline: scrapuje wyniki wyszukiwania, wyciąga linki do listingów, a potem odwiedza każdą stronę detail z rotacyjnym residential proxy.
import requests
from bs4 import BeautifulSoup
from urllib.parse import quote, urljoin
import time
import json
import random
# --- Konfiguracja ProxyHat ---
PROXY_GATEWAY = "http://user-country-US:pass@gate.proxyhat.com:8080"
PROXIES = {"http": PROXY_GATEWAY, "https": PROXY_GATEWAY}
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": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
}
def fetch_search_results(keyword, max_pages=3):
"""Scrap strony wyszukiwania i wyciągnij linki do listingów."""
listing_urls = []
for page in range(1, max_pages + 1):
url = f"https://www.etsy.com/search?q={quote(keyword)}&page={page}"
resp = requests.get(url, headers=HEADERS, proxies=PROXIES, timeout=30)
resp.raise_for_status()
soup = BeautifulSoup(resp.text, "html.parser")
links = soup.select("a.listing-link")
for link in links:
href = link.get("href", "")
if "/listing/" in href:
full_url = urljoin("https://www.etsy.com", href.split("?")[0])
listing_urls.append(full_url)
time.sleep(random.uniform(2, 4)) # uszanuj serwer
return list(set(listing_urls))
def fetch_listing_detail(url):
"""Scrap stronę detail listingu."""
# Sticky session — to samo IP na kilka żądań w ramach jednego sklepu
session = requests.Session()
session.headers.update(HEADERS)
session.proxies = PROXIES
resp = session.get(url, timeout=30)
resp.raise_for_status()
soup = BeautifulSoup(resp.text, "html.parser")
# Tytuł
title_el = soup.select_one("h1[data-buy-box-label='title']") or soup.select_one("h1")
title = title_el.get_text(strip=True) if title_el else ""
# Cena
price_el = soup.select_one("span.currency-value")
price = price_el.get_text(strip=True) if price_el else ""
# Opis
desc_el = soup.select_one("div[data-product-description]") or soup.select_one("#description-text")
description = desc_el.get_text(strip=True)[:500] if desc_el else ""
# Nazwa sklepu
shop_el = soup.select_one("a.shop-name") or soup.select_one("span.shop-name")
shop_name = shop_el.get_text(strip=True) if shop_el else ""
return {
"url": url,
"title": title,
"price": price,
"shop_name": shop_name,
"description": description,
}
def main():
keyword = "funny coffee mug"
print(f"Scrapowanie wyników wyszukiwania dla: {keyword}")
urls = fetch_search_results(keyword, max_pages=3)
print(f"Znaleziono {len(urls)} unikalnych listingów")
results = []
for i, url in enumerate(urls[:10]): # limit do 10 dla przykładu
print(f"[{i+1}/10] {url}")
try:
detail = fetch_listing_detail(url)
results.append(detail)
except Exception as e:
print(f" Błąd: {e}")
time.sleep(random.uniform(3, 6))
print(json.dumps(results, indent=2, ensure_ascii=False))
if __name__ == "__main__":
main()
Tip: Do pobierania detail pages używaj sticky sessions — dodaj flagęsessiondo username w ProxyHat:user-country-US-session-abc123:pass@gate.proxyhat.com:8080. To zapewni, że wszystkie żądania w ramach jednej sesji pójdą z tego samego IP, co wygląda naturalniej dla Cloudflare.
Analityka sklepów — co możesz wyciągnąć
Etsy ujawnia więcej danych o sklepach niż większość marketplace'ów. Oto co możesz systematycznie zbierać:
Liczba sprzedaży — badge "X Sales"
Etsy wyświetla przybliżoną liczbę sprzedaży jako badge na stronie sklepu. Selektor: span.shop-sold-badge lub tekst zawierający "Sales". Wartość jest zaokrąglona (np. "5,000 Sales", "234 Sales"), ale wciąż użyteczna do szacowania skali sprzedawcy.
Liczba listingów
Na stronie sklepu znajdziesz informację o liczbie aktywnych listingów. To wskaźnik tego, jak aktywny jest sprzedawca — sklep z 5 listingami to inna kategoria niż sklep z 500.
Recenzje i oceny
Etsy pokazuje recenzje na dwóch poziomach:
- Recenzje produktu — na stronie listingu
- Recenzje sklepu — na stronie sklepu (
https://www.etsy.com/shop/SHOP_NAME/reviews)
def fetch_shop_stats(shop_name, proxy_url=None):
"""Wyciągnij statystyki sklepu z Etsy."""
proxies = {"http": proxy_url, "https": proxy_url} if proxy_url else None
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}
url = f"https://www.etsy.com/shop/{shop_name}"
resp = requests.get(url, headers=headers, proxies=proxies, timeout=30)
soup = BeautifulSoup(resp.text, "html.parser")
# Sprzedaże
sales = ""
sales_el = soup.select_one("[data-sales]") or soup.find(string=re.compile(r'\d+[,.]?\d*\s*Sales?'))
if sales_el:
sales = sales_el.get_text(strip=True) if hasattr(sales_el, 'get_text') else str(sales_el)
# Liczba listingów
listing_count = len(soup.select("a.listing-link"))
# Ocena
rating_el = soup.select_one("span.screen-reader-only")
rating = rating_el.get_text(strip=True) if rating_el else ""
return {
"shop": shop_name,
"sales": sales,
"listing_count": listing_count,
"rating": rating,
}
proxy = "http://user-country-US:pass@gate.proxyhat.com:8080"
print(fetch_shop_stats("SmallBusinessExample", proxy_url=proxy))
Co z tych danych wyciągnąć?
- Stosunek sprzedaży do listingów — jeśli sklep ma 10 listingów i 50 000 sprzedaży, to znak, że nisza ma duży popyt
- Średnia cena w niszy — czy rynek premium czy budżetowy
- Rozkład ocen — niska ocena = szansa na lepszy produkt
- Trendy sezonowe — śledź, kiedy listingi zyskują na popularności
Etyka — Etsy to małe biznesy, nie korporacje
To najważniejsza sekcja tego przewodnika. Etsy to platforma dla małych, niezależnych twórców. Kiedy scrapujesz Etsy, masz dostęp do danych o prawdziwych ludziach, którzy często inwestują oszczędności życia w swój sklep.
Czego NIE robić
- Nie kopiuj designów — scrapowanie po to, żeby skopiować czyjeś projekty mugów, koszulek czy plakatów, to kradzież intelektualna
- Nie masowo pobieraj obrazów — pobieranie tysięcy zdjęć produktów do trenowania AI bez zgody to naruszenie praw autorskich
- Nie spamuj sprzedawców — nie używaj danych kontaktowych do masowego cold emailingu
- Nie obciążaj serwerów — zachowaj rozsądne opóźnienia między żądaniami (3–6 sekund)
Co JEST w porządku
- Badanie trendów — analizowanie, które kategorie rosną i które słabną
- Analiza cenowa — zrozumienie, jak kształtują się ceny w niszy
- Identyfikacja luk w rynku — znajdowanie podnisz z popytem, ale słabą ofertą
- Monitorowanie własnej marki — śledzenie, czy ktoś nie narusza Twoich praw autorskich
- Budowanie narzędzi analitycznych — SaaS do researchu rynku (podobnie jak eRank czy Marmalead)
Złota zasada: Scrapuj Etsy po to, żeby lepiej zrozumieć rynek i stworzyć lepszy produkt — nie po to, żeby ukraść czyjeś pomysły.
Najlepsze praktyki — podsumowanie techniczne
- Używaj residential proxy — datacenter IP są masowo blokowane na Etsy. ProxyHat oferuje residential IP z geo-targetingiem — sprawdź dostępne lokalizacje.
- Rotuj IP na każde żądanie do stron wyszukiwania; używaj sticky sessions do detail pages
- Dodaj opóźnienia — 3–6 sekund między żądaniami, 10–15 sekund po otrzymaniu 429
- Używaj realistycznych nagłówków — User-Agent, Accept-Language, Referer
- Obsługuj błędy — 403 (Cloudflare block), 429 (rate limit), 503 (temporary)
- Cache'uj wyniki — nie scrapuj tej samej strony dwa razy bez powodu
- Szacuj limity — przy 60 żądań/minutę/IP i rotacji residential proxy, możesz realistycznie pobrać ~3 600 stron na godzinę
Kluczowe wnioski
- Etsy jest chronione przez Cloudflare — residential proxy to wymóg, nie opcja
- Struktura Etsy: wyszukiwanie → listing detail → shop page — każdy poziom daje inne dane
- Dla odkrywania nisz: scrapuj sugestie wyszukiwania, licz sprzedawców w niszy, analizuj ceny
- Dla analityki sklepów: wyciągaj badge sprzedaży, licz listingów, recenzje
- Używaj ProxyHat z flagą
countryisessionw username dla geo-targetingu i sticky sessions - Etyka jest kluczowa — scrapuj dla researchu, nie dla kopiowania designów
- Zacznij od małej skali, dodaj opóźnienia, i dopiero potem zwiększaj wolumen
Jeśli szukasz reliable residential proxy do scrapowania Etsy, sprawdź plany ProxyHat — z geo-targetingiem w ponad 190 krajach i rotacją IP na każde żądanie. Więcej o scrapowaniu w praktyce znajdziesz w naszym przewodniku po residential proxy.






