eBay является одной из крупнейших торговых площадок в интернете, и каждое публичное объявление содержит структурированные данные, необходимые для отслеживания цен, исследования конкурентов и анализа рынка: название, цену, состояние товара, стоимость доставки, данные продавца и ссылку на объявление. Сложность в том, что eBay рендерит цены и большую часть деталей объявлений с помощью JavaScript и активно противодействует автоматическому трафику, поэтому обычный HTTP-запрос возвращает почти пустую страницу вместо нужных данных.

В этом руководстве показано, как надёжно парсить eBay с помощью JavaScript и Node.js. Вы создадите небольшой работающий скрипт, который получает отрендеренную страницу поиска или карточку товара eBay через Crawling API, разбирает каждый результат с помощью cheerio и выводит структурированную запись для каждого товара. Всё руководство ограничено данными публичных объявлений, а раздел о законности в конце не является формальностью, поэтому прочитайте его перед реальным использованием.

Что вы создадите

Скрипт на Node.js, который принимает публичный URL поиска eBay, получает отрендеренный HTML через Crawling API и извлекает структурированную запись для каждого объявления на странице результатов. В качестве примера используется поиск по категории, из которого извлекаются следующие поля:

  • Название наименование объявления, например "Apple iPhone 14 Pro Max 128GB Unlocked".
  • Цена заявленная цена, например "$1,429.49".
  • Состояние состояние товара, например "Brand New" или "Pre-Owned".
  • Доставка стоимость доставки или "Free shipping", если указано.
  • Продавец имя продавца или магазина, если отображается на карточке.
  • URL товара ссылка на страницу конкретного объявления.

Почему обычный запрос не работает на eBay

Если запросить URL поиска eBay с помощью обычного HTTP-клиента, вы получите ответ со статусом 200 и лишь частью данных объявления в теле. Два фактора работают против вас. Во-первых, eBay рендерит цены, стоимость доставки и другие детали объявлений в браузере с помощью JavaScript, поэтому исходный HTML неполон до выполнения скриптов страницы. Во-вторых, eBay быстро выявляет автоматический трафик: IP-адреса датацентров и паттерны запросов, не характерные для реального браузера, блокируются или получают капчу ещё до получения отрендеренного контента.

Поэтому работающий парсер eBay требует двух вещей в одном запросе: браузера, который реально рендерит страницу, и IP-адреса, который платформа воспринимает как реального пользователя. Можно собрать это самостоятельно, используя headless-браузер и пул ротируемых резидентских прокси, но поддерживать всё это в рабочем состоянии и есть основная часть работы. Crawling API объединяет оба требования в одном вызове: вы отправляете URL с JavaScript-токеном, API рендерит страницу за надёжным IP и возвращает готовый HTML для разбора.

Зачем нужен JS-токен

Crawlbase предлагает два типа токенов. Обычный токен получает статический HTML; JavaScript (JS) токен сначала рендерит страницу в реальном браузере. eBay загружает ключевые поля объявлений на стороне клиента, поэтому JS-токен даёт наиболее полную страницу. Использование обычного токена может вернуть неполный результат с отсутствующими ценами или стоимостью доставки, что делает разбор ненадёжным.

Предварительные требования

Перед написанием кода необходимо подготовить несколько вещей. Это не займёт много времени.

Базовые знания JavaScript и Node.js. Вы должны уметь писать и запускать скрипты Node и устанавливать пакеты через npm. Если вы новичок в Node, официальная документация и любой вводный курс дадут необходимую базу. Для более полного погружения см. наше руководство по созданию веб-парсера с Node.js.

Node.js версии 16 или выше. Проверьте версию командой node --version. Если её нет, установите с сайта Node.js или через менеджер версий, например nvm.

Аккаунт Crawlbase и JS-токен. Зарегистрируйтесь, откройте панель управления и скопируйте JavaScript (JS) токен со страницы документации аккаунта. Обращайтесь с токеном как с паролем: он аутентифицирует ваши запросы, поэтому не добавляйте его в систему контроля версий.

Настройка проекта

Создайте папку проекта, инициализируйте её и установите две библиотеки, необходимые парсеру.

bash
node --version

mkdir ebay-scraper && cd ebay-scraper
npm init -y

npm install crawlbase cheerio

Две зависимости выполняют всю работу: crawlbase, официальный Node-клиент для Crawling API, а cheerio разбирает возвращаемый HTML с jQuery-подобным API, позволяя извлекать поля по CSS-селекторам. Если селекторы для вас новинка, руководство по XPath и CSS-селекторам станет хорошим дополнением.

Шаг 1: получение отрендеренной страницы поиска

Начните с получения готовой страницы. Импортируйте класс CrawlingAPI, инициализируйте его с вашим JS-токеном и запросите URL поиска. Проверка статус-кода перед разбором позволяет явно обнаруживать ошибки.

javascript
const { CrawlingAPI } = require('crawlbase');

const api = new CrawlingAPI({ token: 'YOUR_CRAWLBASE_JS_TOKEN' });

async function crawl(pageUrl) {
  const options = { ajax_wait: 'true', page_wait: 5000 };
  const response = await api.get(pageUrl, options);
  if (response.statusCode === 200) {
    return response.body;
  }
  console.error(`Request failed: ${response.statusCode}`);
  return null;
}

const searchUrl = 'https://www.ebay.com/sch/i.html?_nkw=smartphone';
crawl(searchUrl).then((html) => {
  console.log(html ? html.slice(0, 500) : 'No HTML returned');
});

Два параметра ожидания важны для клиентски рендеримых целей. ajax_wait указывает API ждать завершения загрузки асинхронного контента, а page_wait выдерживает фиксированное количество миллисекунд после загрузки, чтобы элементы с поздним рендерингом появились до захвата страницы. Пять секунд, разумная отправная точка; увеличьте значение, если цены или стоимость доставки возвращаются пустыми. Запустите скрипт командой node scraper.js, вы должны увидеть реальную разметку объявлений, а не пустую оболочку. Это подтверждает работу рендеринга перед написанием первого селектора.

Crawlbase eBay Scraper

eBay требует отрендеренную страницу за надёжным IP в одном вызове. Crawling API принимает JS-токен, запускает страницу в реальном браузере, ротирует резидентские IP на стороне сервера и возвращает готовый HTML, избавляя вас от необходимости управлять парком headless-браузеров и пулом прокси. Начните с публичной страницы поиска на бесплатном тарифе.

Шаг 2: разбор каждого объявления с помощью cheerio

Получив отрендеренный HTML, загрузите его в cheerio и обойдите карточки результатов. eBay размещает каждый результат поиска в повторяющемся блоке, поэтому выбираются все карточки, а затем из каждой считываются название, цена, состояние, доставка, продавец и ссылка на товар. Защитное считывание каждого поля не позволяет одному отсутствующему значению прервать выполнение.

javascript
const cheerio = require('cheerio');

function parseSearch(html) {
  const $ = cheerio.load(html);
  const items = [];

  $('li.s-item').each((_, el) => {
    const card = $(el);
    const title = card.find('.s-item__title').text().trim();
    if (!title || title === 'Shop on eBay') return;

    items.push({
      title,
      price: card.find('.s-item__price').text().trim() || null,
      condition: card.find('.SECONDARY_INFO').text().trim() || null,
      shipping: card.find('.s-item__shipping').text().trim() || null,
      seller: card.find('.s-item__seller-info-text').text().trim() || null,
      itemUrl: card.find('a.s-item__link').attr('href') || null,
    });
  });

  return items;
}

Несколько деталей делают код устойчивым. Первая карточка на каждой странице результатов eBay является рекламным заполнителем с заголовком "Shop on eBay", поэтому ранний return пропускает её. Каждое поле возвращает null, если элемент отсутствует, что нередко бывает, поскольку не каждое объявление содержит имя продавца или отдельную строку доставки. URL товара считывается из атрибута href ссылки, а не из её текста, поэтому используется attr вместо text.

Селекторы меняются

Имена классов eBay (s-item, s-item__price, SECONDARY_INFO и остальные) изменяются без предупреждения, причём они различаются между страницами поиска и страницами отдельных объявлений. Считайте приведённые выше селекторы начальным шаблоном, а не контрактом. Если поле возвращается как null, проверьте живую страницу в инструментах разработчика браузера и обновите селектор. Периодическое обновление селекторов нормально для любого производственного парсера.

Шаг 3: объединяем всё вместе

Теперь объедините получение данных и их разбор в один работающий скрипт. Получите отрендеренный HTML, передайте его парсеру и выведите структурированные записи.

javascript
const { CrawlingAPI } = require('crawlbase');
const cheerio = require('cheerio');

const api = new CrawlingAPI({ token: 'YOUR_CRAWLBASE_JS_TOKEN' });

async function crawl(pageUrl) {
  const options = { ajax_wait: 'true', page_wait: 5000 };
  const response = await api.get(pageUrl, options);
  if (response.statusCode === 200) return response.body;
  console.error(`Request failed: ${response.statusCode}`);
  return null;
}

function parseSearch(html) {
  const $ = cheerio.load(html);
  const items = [];
  $('li.s-item').each((_, el) => {
    const card = $(el);
    const title = card.find('.s-item__title').text().trim();
    if (!title || title === 'Shop on eBay') return;
    items.push({
      title,
      price: card.find('.s-item__price').text().trim() || null,
      condition: card.find('.SECONDARY_INFO').text().trim() || null,
      shipping: card.find('.s-item__shipping').text().trim() || null,
      seller: card.find('.s-item__seller-info-text').text().trim() || null,
      itemUrl: card.find('a.s-item__link').attr('href') || null,
    });
  });
  return items;
}

async function main() {
  const searchUrl = 'https://www.ebay.com/sch/i.html?_nkw=smartphone';
  const html = await crawl(searchUrl);
  if (!html) return;
  const items = parseSearch(html);
  console.log(JSON.stringify(items.slice(0, 3), null, 2));
}

main();

Как выглядит результат

Запустите полный скрипт командой node scraper.js, и вы получите чистый массив записей, по одной на каждое объявление, готовый для записи в JSON, CSV или базу данных.

json
[
  {
    "title": "Apple iPhone 14 Pro Max 128GB Unlocked New Sealed",
    "price": "$1,429.49",
    "condition": "Brand New",
    "shipping": "Free shipping",
    "seller": "beyond_theworld (4,512)",
    "itemUrl": "https://www.ebay.com/itm/354586733872"
  },
  {
    "title": "Apple iPhone X 64GB Unlocked Good Refurbished",
    "price": "$249.99",
    "condition": "Pre-Owned",
    "shipping": "+$12.50 shipping",
    "seller": "thetechout (1,685)",
    "itemUrl": "https://www.ebay.com/itm/393541114176"
  }
]

Обход страниц результатов

Одна страница результатов, это демонстрация; реальная задача обходит разбивку на страницы. eBay передаёт номер страницы через параметр запроса _pgn, поэтому можно строить URL каждой страницы в цикле, получать её через Crawling API, разбирать той же функцией и собирать строки. Поскольку все страницы результатов имеют одинаковую структуру карточек, написанный парсер работает на всех без изменений.

javascript
async function scrapePages(keyword, totalPages) {
  const all = [];
  for (let page = 1; page <= totalPages; page++) {
    const url =
      `https://www.ebay.com/sch/i.html?_nkw=${encodeURIComponent(keyword)}&_pgn=${page}`;
    const html = await crawl(url);
    if (html) all.push(...parseSearch(html));
  }
  return all;
}

scrapePages('smartphone', 3).then((rows) => {
  console.log(`Collected ${rows.length} listings`);
});

Чтобы обогатить каждую строку подробностями (описанием, всеми изображениями, полной таблицей доставки, отзывами о продавце), возьмите itemUrl из каждой карточки и получите страницу этого отдельного объявления через ту же функцию crawl, затем напишите небольшой парсер для макета страницы объявления. Принцип идентичен: рендеринг, затем разбор. Подробнее о целях с тяжёлым рендерингом см. руководство по обходу JavaScript-сайтов.

Как оставаться незаблокированным

Даже при наличии рендеринга eBay отслеживает трафик, характерный для парсеров. Несколько привычек помогут поддерживать работоспособность, и они применимы к любой сложной коммерческой цели.

  • Соблюдайте темп запросов. Частые запросы в плотном цикле, самый быстрый способ попасть под ограничения. Распределяйте запросы и варьируйте ключевые слова, а не проходите один путь на полной скорости.
  • Используйте ротацию. Пул резидентских IP распределяет запросы по множеству адресов реальных пользователей, чтобы ни один из них не превысил лимит. Crawling API делает это за вас; если вы строите собственный стек, это ключевой компонент.
  • Следите за статус-кодами. Если сессия начинает возвращать капчи или ошибки, это сигнал о том, что текущая частота запросов или IP-уровень уже недостаточны. Воспринимайте это как повод снизить активность, а не как шум.

Общую стратегию см. в статьях о том, как парсить сайты без блокировок и как обходить капчи при парсинге. Если вы предпочитаете маршрутизировать собственный трафик через ротируемый пул вместо управляемого API, Smart AI Proxy предоставляет ту же ротацию резидентских IP как сквозной прокси-эндпоинт. eBay также является частой целью для более широкого парсинга электронной коммерции, где тот же принцип получения и разбора данных применяется на разных сайтах.

Законно ли парсить eBay?

Допустимость парсинга eBay зависит от условий использования eBay, вашей юрисдикции и того, что вы делаете с данными. Условия использования eBay ограничивают автоматический доступ, поэтому парсинг может нарушать их независимо от тщательности вашего инструментария. Код в этом руководстве этого не меняет; он лишь делает техническую часть рабочей. Прочитайте Пользовательское соглашение eBay и его robots.txt и воспринимайте оба документа как границы того, что вы можете собирать.

Несколько правил, которых стоит придерживаться. Собирайте только публичные данные объявлений: название, цену, состояние, стоимость доставки, имя продавца, как оно отображается на карточке, и ссылку на товар, видимую без аккаунта. Соблюдайте ожидаемый eBay темп запросов и поддерживайте объём достаточно низким, чтобы не нагружать серверы. Избегайте персональных данных, включая всё, что связано с идентифицируемыми покупателями или продавцами, помимо публично указанного на странице результатов. Если вы планируете коммерческое использование данных, получите разрешение или официальное соглашение, а не считайте молчание согласием.

Для крупного или коммерческого использования eBay предлагает официальные API, включая Browse API и Finding API, и это правильные инструменты, когда вам нужны большие объёмы, гарантированная структура или коммерческие права. Данное руководство намеренно ограничено публичными страницами объявлений и поиска, поскольку это граница, делающая работу обоснованной. Оно не охватывает ничего за логином, персональные данные покупателей или продавцов, личные сообщения между пользователями, данные аккаунта или заказов, закрытых авторизацией, или попыток обхода аутентификации. Если вашему проекту нужно больше, чем публичные объявления, официальные API eBay или соглашение о данных, правильный путь, а не более изощрённый парсер.

Итоги

Ключевые выводы

  • eBay рендерит объявления на стороне клиента. Обычный запрос возвращает неполную страницу, поэтому необходим рендеринг перед разбором.
  • Нужны рендеринг и надёжный IP вместе. Crawling API с JS-токеном делает оба в одном вызове; ajax_wait и page_wait управляют временем ожидания контента.
  • cheerio выполняет извлечение. Выбирайте все карточки s-item, затем сопоставляйте название, цену, состояние, доставку, продавца и URL с актуальными селекторами, и рассчитывайте на их обновление.
  • Масштабирование через обход страниц. Параметр _pgn перебирает страницы результатов, и тот же парсер работает на каждой при разумном темпе запросов.
  • Оставайтесь в рамках публичных данных. Соблюдайте ToS и robots.txt eBay, предпочитайте официальный Browse или Finding API для крупного или коммерческого использования и никогда не трогайте авторизацию, личные данные или личные сообщения.

Часто задаваемые вопросы

Почему обычный запрос возвращает неполные данные с eBay?

Потому что eBay рендерит цены, стоимость доставки и большую часть деталей объявлений на стороне клиента с помощью JavaScript. Исходный HTML неполон до выполнения скриптов страницы в браузере, поэтому сырой HTTP-запрос возвращает статус 200 с отсутствующими или пустыми ключевыми полями. Для получения полной страницы необходим её рендеринг, чем занимается JS-токен Crawling API.

Нужен обычный токен или JS-токен для eBay?

Используйте JS-токен. Обычный токен получает статический HTML, который на eBay может вернуться с отсутствующими ценами или стоимостью доставки. JS-токен рендерит страницу в реальном браузере перед возвратом HTML, поэтому поля объявления присутствуют, когда cheerio разбирает их.

Мои селекторы возвращают null. Что изменилось?

Почти наверняка разметка eBay. Классы карточки s-item, маркеры SECONDARY_INFO и обёртки секций изменяются без предупреждения, причём различаются между страницами поиска и страницами отдельных объявлений, поэтому работавшие ранее селекторы могут перестать работать. Проверьте живую страницу в инструментах разработчика браузера и обновите селекторы. Периодическое обновление селекторов нормально для любого производственного парсера.

Использовать официальный API eBay или парсить сайт?

Если вам нужны объёмы, гарантированная структура или права коммерческого переиспользования, используйте официальный Browse или Finding API eBay. Они созданы именно для этого и позволяют оставаться в рамках условий eBay. Парсинг публичных объявлений подходом из этого руководства подходит для небольших исследований публичных данных, где API недоступен, при условии соблюдения ToS, robots.txt и лимитов.

Можно ли парсить персональные данные покупателей или продавцов с eBay?

Нет, и это руководство не охватывает такой сценарий. Данные покупателей, личные сообщения и данные аккаунтов находятся за авторизацией, поэтому они не являются публичными данными. Парсинг контента за авторизацией, персональных данных или обход аутентификации для их получения выходит за рамки данного руководства и нарушает условия eBay. Для санкционированного доступа правильный путь, официальный API eBay или лицензионное соглашение.

Как избежать блокировки при парсинге eBay?

Поддерживайте низкую частоту запросов на IP, варьируйте ключевые слова вместо зацикливания на одном пути и маршрутизируйте через ротируемые резидентские IP, чтобы ни один адрес не превысил лимит. Crawling API управляет ротацией и пулом надёжных IP; если вы строите собственный стек, вложитесь именно в это. Следите за статус-кодами и снижайте активность при появлении проверок.

Начать создавать

Обходите любой сайт в масштабе, без борьбы с инфраструктурой.

Crawlbase берёт на себя прокси, отпечатки и CAPTCHA, чтобы ваша команда выпускала конвейеры данных вместо поддержки обвязки краулинга. 1 000 запросов бесплатно, без карты.

Самообслуживание · Звонок отдела продаж не требуется · Доступны корпоративные объёмы краулинга