Скрапинг Etsy: API или HTML — с чего начать
Etsy предоставляет Open API v3, но он спроектирован для seller-tools и требует OAuth. Эндпоинты вроде /v3/application/shops и /v3/application/listings доступны только через приложение, одобренное Etsy. Для нишевых исследований — поиска трендов, анализа конкурентов, оценки цен — HTML-поверхность остаётся единственным реальным вариантом. API не отдаёт данные о продажах магазинов, не показывает трендовые поисковые запросы и не даёт доступа к дереву категорий. В этом руководстве — структура Etsy, защита от ботов, конкретные паттерны скрапинга и рабочие примеры на Python.
Структура Etsy: что и как скрапить
Страницы поиска
URL поиска: https://www.etsy.com/search?q=mug+design. Результаты загружаются серверным рендерингом — карточки товаров доступны в HTML без JavaScript. Пагинация — параметр &page=2 в URL. Etsy показывает до ~500 страниц результатов, но для нишевых исследований обычно достаточно первых 5–10.
Ключевые CSS-селекторы для страницы поиска:
- Контейнер результатов:
div[data-results] - Карточки товаров:
div[data-results] .v2-listing-cardили[data-listing-id] - Название:
.v2-listing-card__info h3 - Цена:
.currency-value - Рейтинг:
.v2-listing-card__info .star-rating - Ссылка на товар:
a.listing-link(атрибутhref) - Общее число результатов:
.wt-text-gray .wt-mb-xs-0(текст «X,XXX results»)
Страницы товаров (листинги)
URL листинга: https://www.etsy.com/listing/123456789/item-name. Etsy рендерит ключевые данные через JSON в теге <script type="application/ld+json"> — это самый надёжный способ извлечения структурированных данных, не зависящий от CSS-классов.
Что извлекаем из листинга:
- Заголовок, описание, цена, валюта: из
ld+jsonблока (@type: Product) - Продавец:
a[data-shop-id]— имя и ID магазина - Количество продаж продавца: текст бейджа «X sales» рядом с именем
- Изображения:
img[data-src-zoom] - Варианты:
[data-variation-id]
Страницы магазинов
URL магазина: https://www.etsy.com/shop/ShopName. Etsy публично показывает бейдж «X sales» — это приблизительное число продаж с точностью ±10%. Количество листингов — через пагинацию: /shop/ShopName?section_id=0&page=2. Отзывы: /shop/ShopName/reviews.
Дерево категорий
Etsy организует товары в иерархию: https://www.etsy.com/c/clothing, /c/clothing/womens-clothing и так далее. Навигационное меню содержит ссылки на все верхние категории. Подкатегории извлекаются рекурсивно через ссылки на страницах категорий — селектор a[href*="/c/"]. Для POD-исследований категории — отправная точка: от них можно идти вниз до конкретных подкатегорий и оценивать конкуренцию.
Антибот Etsy: Cloudflare и лимиты запросов
Etsy использует двухуровневую защиту:
- Cloudflare WAF — JavaScript-челленджи и rate-limiting на уровне CDN. При подозрении Cloudflare показывает interstitial-страницу или 403. Residential-прокси значительно снижают вероятность челленджа, потому что IP выглядит как реальный пользователь из домашней сети.
- Внутренние лимиты Etsy — отслеживание частоты запросов с одного IP. Порог: примерно 100–200 запросов за 10–15 минут до появления 429 Too Many Requests. Лимиты строже для страниц поиска, чем для страниц отдельных листингов.
Практические правила:
- Держите 1–2 запроса в секунду на один IP.
- Ротируйте IP каждые 50–80 запросов.
- Используйте residential-прокси — datacenter-IP Etsy блокирует агрессивнее.
- Добавляйте реалистичные заголовки:
User-Agent,Accept,Accept-Language,Referer. - Не пытайтесь программно обходить Cloudflare-челлендж — это эскалирует блокировку до банлиста.
Выбор типа прокси для Etsy
| Тип прокси | Обход Cloudflare | Скорость | Рекомендация для Etsy |
|---|---|---|---|
| Residential | Отлично | Средняя (1–3 с) | Лучший выбор — IP реальных пользователей |
| Mobile | Отлично | Ниже (2–5 с) | Хорошо для sticky-сессий |
| Datacenter | Плохо | Высокая (<0.5 с) | Только для невысоких объёмов |
Для нишевых исследований на Etsy мы рекомендуем residential-прокси с ротацией по запросам. Настройка ProxyHat:
# HTTP residential proxy — ротация IP по каждому запросу
http://user-country-US:YOUR_PASSWORD@gate.proxyhat.com:8080
# Sticky-сессия для многостраничного скрапинга магазина
http://user-session-shop1:YOUR_PASSWORD@gate.proxyhat.com:8080
# Городское таргетирование — IP из конкретного города
http://user-country-US-city-new_york:YOUR_PASSWORD@gate.proxyhat.com:8080Подробнее о доступных локациях — на странице ProxyHat Locations.
Паттерны скрапинга для поиска ниш
Трендовые поисковые запросы
Etsy не показывает трендовые запросы напрямую, но подстрока автодополнения доступна по адресу:
# Пример: автодополнения для запроса "mug"
curl -x http://user-country-US:YOUR_PASSWORD@gate.proxyhat.com:8080 \
-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)" \
-H "Accept: application/json" \
"https://www.etsy.com/api/v3/ajax/member/search-suggestions?query=mug"Ответ — JSON с массивом предложений. Пример усечённого ответа:
{
"results": [
{"query": "mug", "display_name": "mug"},
{"query": "mug rug", "display_name": "mug rug"},
{"query": "mug holder", "display_name": "mug holder"},
{"query": "mug cozy", "display_name": "mug cozy"},
{"query": "mug tree", "display_name": "mug tree"},
{"query": "mug personalized", "display_name": "mug personalized"}
]
}Собирая подсказки для сотен seed-запросов, вы получаете карту спроса в категории. Для POD это особенно ценно: подсказки вроде «mug cozy» или «mug rug» указывают на субниши с меньшей конкуренцией.
Количество продавцов в нише
На странице поиска Etsy показывает «X,XXX results» — это общее число товаров, а не продавцов. Но каждый товар привязан к магазину. Собирая уникальные shop_id со страниц поиска, вы получаете оценку конкуренции. Алгоритм: скрапить 5–10 страниц результатов → извлечь data-shop-id из каждой карточки → посчитать уникальные значения.
Средние цены и ценовые сегменты
Извлекайте цены из карточек поиска и вычисляйте медиану, 25-й и 75-й перцентили. Это показывает, что покупатели готовы платить в данной нише — критически важно для POD-ценообразования. Если медианная цена кружки — $16, а вы планируете продавать за $30, это сигнал к пересмотру дизайна или позиционирования.
Полный цикл нишевого анализа
- Seed-запросы: соберите 50–100 ключевых слов через автодополнение.
- Объём результатов: для каждого запроса получите «X results» со страницы поиска.
- Конкуренция: извлеките уникальные shop_id — сколько продавцов в нише.
- Цены: соберите цены, вычислите статистику.
- Анализ лидеров: топ-10 магазинов по продажам — что они продают, как оформляют.
- Решение: ниша с <500 продавцов, медианная цена >$15 и растущим числом результатов — перспективна для POD.
Скрапинг поиска Etsy на Python
Ниже — полный пример: запрос страницы поиска → парсинг карточек → сбор данных для нишевого анализа.
import requests
from bs4 import BeautifulSoup
import re
import time
import random
import json
PROXY_USER = "user-country-US"
PROXY_PASS = "YOUR_PASSWORD"
PROXY_URL = f"http://{PROXY_USER}:{PROXY_PASS}@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": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Referer": "https://www.etsy.com/",
}
def fetch_search(query, page=1):
"""Получить страницу поиска Etsy."""
url = f"https://www.etsy.com/search?q={query}&page={page}"
resp = requests.get(url, headers=HEADERS, proxies=PROXIES, timeout=15)
resp.raise_for_status()
return resp.text
def parse_search_results(html):
"""Извлечь данные из карточек товаров."""
soup = BeautifulSoup(html, "html.parser")
listings = []
cards = soup.select("div[data-results] .v2-listing-card")
if not cards:
cards = soup.select("[data-listing-id]")
for card in cards:
link = card.select_one("a.listing-link")
title_el = card.select_one("h3")
price_el = card.select_one(".currency-value")
shop_el = card.select_one("[data-shop-id]")
listing = {
"title": title_el.get_text(strip=True) if title_el else None,
"url": link["href"] if link and link.get("href") else None,
"price": price_el.get_text(strip=True) if price_el else None,
"listing_id": card.get("data-listing-id"),
"shop_id": shop_el.get("data-shop-id") if shop_el else None,
}
if listing["url"]:
listings.append(listing)
# Общее число результатов
results_text = soup.select_one(".wt-text-gray")
total = None
if results_text:
match = re.search(r"([\d,]+)\s+results", results_text.get_text())
if match:
total = int(match.group(1).replace(",", ""))
return {"listings": listings, "total_results": total}
# Собираем данные по нише
niche_data = []
for page in range(1, 6):
html = fetch_search("custom+mug", page=page)
result = parse_search_results(html)
niche_data.extend(result["listings"])
print(f"Page {page}: {len(result['listings'])} listings, "
f"total: {result['total_results']}")
time.sleep(random.uniform(2.0, 4.0))Детальные страницы товаров с ротацией прокси
При переходе к страницам товаров важно ротировать IP, чтобы не упереться в лимиты. ProxyHat позволяет управлять ротацией через параметр session в имени пользователя — каждый новый session_id = новый IP.
def fetch_listing_detail(listing_url, session_id):
"""Получить детальную страницу товара с ротацией прокси."""
proxy = f"http://user-session-{session_id}:{PROXY_PASS}@gate.proxyhat.com:8080"
proxies = {"http": proxy, "https": proxy}
resp = requests.get(listing_url, headers=HEADERS, proxies=proxies, timeout=15)
resp.raise_for_status()
return resp.text
def extract_listing_data(html):
"""Извлечь структурированные данные из ld+json блока."""
soup = BeautifulSoup(html, "html.parser")
data = {}
for script in soup.find_all("script", type="application/ld+json"):
try:
ld = json.loads(script.string)
if ld.get("@type") == "Product":
data["name"] = ld.get("name")
offers = ld.get("offers", {})
data["price"] = offers.get("price")
data["currency"] = offers.get("priceCurrency")
data["description"] = (ld.get("description") or "")[:500]
except (json.JSONDecodeError, TypeError):
continue
# Бейдж продаж продавца
sales_el = soup.select_one("[data-sales-count]")
if not sales_el:
# Fallback: поиск по тексту
for el in soup.select(".wt-text-gray"):
match = re.search(r"(\d[\d,]*)\s+sales?", el.get_text())
if match:
data["seller_sales"] = int(match.group(1).replace(",", ""))
break
# ID и имя магазина
shop_link = soup.select_one("a[data-shop-id]")
if shop_link:
data["shop_id"] = shop_link.get("data-shop-id")
data["shop_name"] = shop_link.get_text(strip=True)
return data
# Собираем детальные данные по листингам
all_details = []
for i, listing in enumerate(niche_data[:25]):
session = f"etsy{i:04d}"
try:
detail_html = fetch_listing_detail(listing["url"], session)
detail = extract_listing_data(detail_html)
detail["search_rank"] = i + 1
all_details.append(detail)
print(f"{i+1}. {detail.get('name', 'N/A')[:60]} — "
f"{detail.get('price', '?')} {detail.get('currency', '')}")
except requests.HTTPError as e:
print(f"{i+1}. HTTP error: {e.response.status_code}")
time.sleep(random.uniform(1.5, 3.0))Аналитика магазинов Etsy
Страница магазина — ключ к пониманию конкуренции. Etsy публично раскрывает:
- Бейдж «X sales» — примерное количество продаж. Для нишевых исследований этого достаточно: сравнивайте продавцов между собой.
- Количество листингов — доступно через пагинацию или атрибут
data-listings-count. - Рейтинг и отзывы —
/shop/ShopName/reviews. Рейтинг и тексты отзывов дают понимание, что ценят покупатели.
def analyze_shop(shop_name):
"""Собрать базовую аналитику магазина Etsy."""
url = f"https://www.etsy.com/shop/{shop_name}"
proxy = f"http://user-country-US:{PROXY_PASS}@gate.proxyhat.com:8080"
proxies = {"http": proxy, "https": proxy}
resp = requests.get(url, headers=HEADERS, proxies=proxies, timeout=15)
soup = BeautifulSoup(resp.text, "html.parser")
shop_data = {"name": shop_name}
# Количество продаж — бейдж «X sales»
for el in soup.select(".wt-text-gray"):
match = re.search(r"(\d[\d,]*)\s+sales?", el.get_text())
if match:
shop_data["sales_count"] = int(match.group(1).replace(",", ""))
break
# Количество листингов
listing_count_el = soup.select_one("[data-listings-count]")
if listing_count_el:
shop_data["listing_count"] = int(
listing_count_el["data-listings-count"]
)
# Рейтинг магазина
rating_el = soup.select_one("[data-rating]")
if rating_el:
shop_data["rating"] = float(rating_el["data-rating"])
return shop_data
# Анализируем уникальные магазины из ниши
unique_shops = set()
for detail in all_details:
if detail.get("shop_name"):
unique_shops.add(detail["shop_name"])
shop_analytics = []
for shop in list(unique_shops)[:10]:
data = analyze_shop(shop)
shop_analytics.append(data)
print(f"{shop}: {data.get('sales_count', '?')} sales, "
f"{data.get('listing_count', '?')} listings, "
f"rating: {data.get('rating', '?')}")
time.sleep(random.uniform(2.0, 4.0))
# Сводная статистика по нише
import statistics
prices = [float(d["price"]) for d in all_details if d.get("price")]
sales = [d["seller_sales"] for d in all_details if d.get("seller_sales")]
print(f"\nНишевая статистика:")
print(f" Медианная цена: ${statistics.median(prices):.2f}")
print(f" 25-й перцентиль: ${statistics.quantiles(prices, n=4)[0]:.2f}")
print(f" 75-й перцентиль: ${statistics.quantiles(prices, n=4)[2]:.2f}")
print(f" Средние продажи продавца: {statistics.mean(sales):.0f}")
print(f" Уникальных магазинов: {len(unique_shops)}")Этика: продавцы Etsy — малый бизнес
Etsy — площадка независимых продавцов. Многие из них — мастера, создающие уникальные товары ручной работы. При скрапинге соблюдайте принципы:
- Исследуйте, не копируйте. Скрапинг для анализа трендов и цен — нормально. Копирование дизайнов, фотографий и описаний — нарушение авторских прав и прямой вред малому бизнесу.
- Соблюдайте robots.txt. Etsy разрешает скрапинг определённых путей — проверяйте
https://www.etsy.com/robots.txtперед запуском. Если путь запрещён — не скрапите его. - Не перегружайте серверы. Держите скорость ≤2 запросов/сек с ротацией IP. Агрессивный скрапинг замедляет сайт для реальных покупателей и продавцов.
- Уважайте авторские права. Дизайны, фотографии и тексты защищены. Используйте данные для исследований рынка, а не для воспроизведения чужого труда.
- GDPR/CCPA. Не собирайте персональные данные продавцов сверх необходимого для аналитики. Имя магазина и количество продаж — достаточно.
Скрапинг Etsy для нишевых исследований — инструмент, а не оружие. Цель — понять рынок и найти свою нишу, а не обмануть продавцов.
Подробнее об этике и лучших практиках скрапинга — в нашем материале о веб-скрапинге и этике.
Ключевые выводы
- Etsy Open API не подходит для нишевых исследований — скрапинг HTML остаётся основным подходом.
- Residential-прокси обязательны: Cloudflare и внутренние лимиты Etsy быстро блокируют datacenter-IP.
- Держите 1–2 запроса/сек, ротируйте IP каждые 50–80 запросов через ProxyHat.
- Структурированные данные в
ld+json— самый надёжный источник на страницах товаров. - Бейдж «X sales» и количество листингов — ключевые метрики для оценки конкуренции в нише.
- API автодополнений — быстрый способ собрать seed-запросы для нишевого анализа.
- Скрапите для исследований, не для копирования. Уважайте труд независимых продавцов.






