Amazon, один из богатейших источников публичных коммерческих данных в интернете: названия товаров, цены, рейтинги, наличие и рейтинги бестселлеров, которые меняются в течение дня. Разовый сбор данных полезен, но настоящая ценность проявляется при сборе по расписанию: тогда можно отслеживать движение цены, момент, когда листинг уходит из наличия, или рост рейтинга за неделю. Единственный ручной запуск не даст ни одного из этих ответов.
Это руководство показывает, как автоматизировать парсинг Amazon с помощью JavaScript и Node.js. Вы создадите скрапер, который получает публичные данные о товарах и результаты поиска через Crawling API, а затем обернёте его в компоненты для автономной работы: запланированное задание по cron, асинхронный Crawler с webhook-коллбэком для крупных запусков, надёжное хранение результатов и обработку повторных попыток, чтобы единственный неудачный запрос не губил весь пакет. Мы ограничим руководство публичными данными о товарах, а раздел о правовых аспектах в конце написан не для галочки, поэтому прочитайте его прежде, чем направить это на реальные объёмы. Если вам нужен только разовый сбор, наши руководства о том, как парсить данные товаров Amazon и как парсить бестселлеры Amazon, охватывают этот случай; данный пост посвящён их запуску в автоматическом режиме.
Что вы создадите
Автоматизацию на Node.js, которая парсит публичные страницы товаров и поиска Amazon по расписанию и сохраняет структурированную запись за каждый запуск. В качестве рабочего примера мы используем страницу результатов поиска и извлекаем следующие поля для каждого элемента:
- ASIN Amazon Standard Identification Number, уникальный идентификатор товара.
- Title название товара, отображаемое на карточке.
- Price указанная цена в виде текста, например "$29.99".
- Rating средняя оценка в звёздах, если она есть.
- Reviews количество отзывов, показанное на карточке.
- Product URL ссылка на страницу отдельного товара.
Вокруг этого скрапера вы добавите четыре компонента автоматизации: планировщик на основе cron, асинхронный запуск с webhook-коллбэком для крупных заданий, JSON-хранилище с ключом по временной метке запуска и обёртку с повторными попытками, обрабатывающую временные сбои без прерывания всего пакета.
Почему обычный запрос не работает на Amazon
Если запросить URL поиска Amazon через простой HTTP-клиент, вы редко получите нужные данные. Amazon рендерит большую часть страницы в браузере и агрессивно проверяет автоматизированный трафик. IP датацентра, обращающийся к страницам товаров в плотном цикле, получает CAPTCHA, заглушку «Robot Check» или прямую блокировку задолго до того, как успеет собрать полезный объём данных. Даже когда запрос проходит, возвращаемая разметка может оказаться усечённой оболочкой без цен и рейтингов.
Таким образом, работающий скрапер Amazon должен объединять в одном запросе: страницу, которая действительно рендерится, и IP, который платформа воспринимает как адрес реального посетителя. Можно собрать это самостоятельно из безголового браузера и пула ротируемых жилых прокси, но их интеграция и поддержание занимает большую часть работы, которая усугубляется при запуске по расписанию, когда сбои накапливаются без надзора. Crawling API объединяет оба компонента в одном вызове: вы отправляете URL, он получает данные за доверенным ротируемым IP и возвращает готовый HTML для парсинга.
Crawlbase выдаёт обычный токен и JavaScript (JS) токен. Обычный токен получает статичный HTML; JS-токен сначала рендерит страницу в реальном браузере, что расходует больше кредитов. Многие страницы поиска и товаров Amazon нормально парсятся с обычным токеном, поэтому начните с него и переходите на JS-токен только если нужное поле возвращается пустым.
Предварительные требования
Перед написанием кода нужно подготовить несколько вещей. Это не займёт много времени.
Базовые знания JavaScript и Node.js. Вы должны уметь писать и запускать Node-скрипт, а также устанавливать пакеты через npm. Если вы новичок в Node, наше руководство о том, как создать веб-скрапер с Node.js, охватывает основы, необходимые для этого туториала.
Node.js 16 или новее. Проверьте версию командой node --version. Если не установлен, скачайте с сайта Node.js или через менеджер версий вроде nvm.
Аккаунт Crawlbase и токен. Зарегистрируйтесь, откройте дашборд и скопируйте токен. Бесплатный тариф включает до 20 000 запросов без карты, чего вполне достаточно для создания и планирования этого задания. Обращайтесь с токеном как с паролем: он аутентифицирует ваши запросы, поэтому не добавляйте его в систему контроля версий и читайте из переменной окружения.
Настройка проекта
Создайте папку проекта, инициализируйте её и установите библиотеки, необходимые для автоматизации.
node --version mkdir amazon-automation && cd amazon-automation npm init -y npm install crawlbase cheerio node-cron
Три зависимости выполняют основную работу: crawlbase, официальный Node-клиент для Crawling API и асинхронного Crawler, cheerio парсит возвращаемый HTML через jQuery-подобный API, позволяя извлекать поля по CSS-селектору, а node-cron запускает скрапер по расписанию из того же процесса. Экспортируйте токен один раз, чтобы все скрипты в папке могли его прочитать:
export CRAWLBASE_TOKEN='YOUR_CRAWLBASE_TOKEN'
Шаг 1: Получение и парсинг страницы поиска
Начните с самого скрапера, поскольку всё остальное автоматизирует именно его. Импортируйте класс CrawlingAPI, инициализируйте его с токеном, запросите URL поиска и разберите карточки каждого результата с помощью cheerio. Проверка кода статуса перед парсингом позволяет обнаруживать ошибки явно, а не скрыто.
const { CrawlingAPI } = require('crawlbase'); const cheerio = require('cheerio'); const api = new CrawlingAPI({ token: process.env.CRAWLBASE_TOKEN }); async function scrapeSearch(searchUrl) { const response = await api.get(searchUrl); if (response.statusCode !== 200) { throw new Error(`Request failed: ${response.statusCode}`); } return parseSearch(response.body); } function parseSearch(html) { const $ = cheerio.load(html); const items = []; $('div[data-asin]').each((_, el) => { const card = $(el); const asin = card.attr('data-asin'); const title = card.find('h2 span').text().trim(); if (!asin || !title) return; items.push({ asin, title, price: card.find('.a-price .a-offscreen').first().text().trim() || null, rating: card.find('.a-icon-alt').first().text().trim() || null, reviews: card.find('.a-size-base.s-underline-text').first().text().trim() || null, productUrl: `https://www.amazon.com/dp/${asin}`, }); }); return items; } const searchUrl = 'https://www.amazon.com/s?k=wireless+headphones'; scrapeSearch(searchUrl).then((items) => { console.log(JSON.stringify(items.slice(0, 3), null, 2)); });
Несколько деталей обеспечивают устойчивость. Amazon снабжает каждую карточку результата атрибутом data-asin, это наиболее стабильный хук на странице, поэтому мы опираемся на него и пропускаем карточки без ASIN и названия (рекламные позиции и пробельные элементы макета часто имеют одно, но не другое). Цена находится в скрытом span .a-offscreen, содержащем чистое отформатированное значение, что надёжнее, чем парсинг разделённой видимой цены. Каждое поле падает в null при отсутствии, так что одно недостающее значение никогда не прерывает выполнение. Сохраните файл как scraper.js и запустите через node scraper.js; вы должны увидеть чистый массив записей о товарах.
Приведённый выше скрапер хорошо работает для одной страницы за раз, но автоматизированное задание, обходящее сотни страниц Amazon по расписанию, именно то место, где синхронное ожидание каждого запроса начинает давить. Асинхронный Crawler принимает ваши URLs, получает каждый за ротируемым доверенным IP и отправляет готовые страницы на webhook под вашим управлением, так что запланированный пакет продолжает работу без управления парком безголовых браузеров или пулом прокси с вашей стороны. Начните с публичных страниц на бесплатном тарифе.
Шаг 2: Сохранение каждого запуска
Автоматизация полезна только при сохранении данных, поэтому записывайте каждый запуск на диск с ключом по временной метке. Это даёт историю для последующего сравнения, позволяющую видеть изменения цен и рейтингов. Плоский JSON-файл на запуск, простейшее надёжное хранилище, которое легко загрузить в любой другой инструмент.
const fs = require('fs'); const path = require('path'); function saveRun(items) { const dir = path.join(__dirname, 'data'); fs.mkdirSync(dir, { recursive: true }); const stamp = new Date().toISOString().replace(/[:.]/g, '-'); const file = path.join(dir, `run-${stamp}.json`); const payload = { scrapedAt: new Date().toISOString(), count: items.length, items }; fs.writeFileSync(file, JSON.stringify(payload, null, 2)); console.log(`Saved ${items.length} items to ${file}`); return file; }
Временная метка в формате ISO сортируется естественным образом, поэтому листинг директории data даёт историю запусков в порядке. Для производственного задания это заменяется базой данных, но контракт тот же: один набор записей за запуск, проставленный временем сбора. Каждый сохранённый файл содержит поле scrapedAt, чтобы при последующем сравнении было понятно, в какой момент относится то или иное значение цены.
Шаг 3: Добавление повторных попыток при временных сбоях
Запланированное задание выполняется без надзора, поэтому единственный ненадёжный запрос не должен прерывать пакет. Оберните запрос в небольшой вспомогательный метод с повторными попытками, который делает паузу между попытками и сдаётся лишь через несколько попыток. Большинство временных сбоев (мимолётная блокировка, медленный рендеринг, сетевой сбой) устраняются при следующей попытке.
function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } async function scrapeWithRetry(url, attempts = 3) { for (let i = 1; i <= attempts; i++) { try { return await scrapeSearch(url); } catch (err) { console.warn(`Attempt ${i} failed: ${err.message}`); if (i === attempts) throw err; await sleep(2000 * i); } } }
Задержка умножается на номер попытки, так что интервалы растут (2 секунды, затем 4, затем 6) вместо того, чтобы долбить уже перегруженный ресурс. После последней попытки ошибка пробрасывается, позволяя вызывающей стороне решить, записать её в журнал и продолжить со следующим ключевым словом или остановить запуск. Именно это различие отделяет планировщик, который восстанавливается самостоятельно, от того, за которым нужно присматривать.
Шаг 4: Планирование через cron
Теперь сделайте это автономным. Пакет node-cron запускает функцию по стандартному cron-выражению из вашего процесса, так что скрапер, хранилище и логика повторных попыток остаются в одном месте. Здесь мы запускаем задание каждое утро в 6:00 и собираем список ключевых слов при каждом запуске.
const cron = require('node-cron'); const keywords = ['wireless headphones', 'mechanical keyboard', 'usb c hub']; async function runJob() { console.log(`Run started at ${new Date().toISOString()}`); const all = []; for (const keyword of keywords) { const url = `https://www.amazon.com/s?k=${encodeURIComponent(keyword)}`; try { const items = await scrapeWithRetry(url); all.push(...items.map((it) => ({ ...it, keyword }))); } catch (err) { console.error(`Skipping "${keyword}": ${err.message}`); } await sleep(3000); } saveRun(all); } cron.schedule('0 6 * * *', runJob); console.log('Scheduler running. Daily job at 06:00.');
Выражение 0 6 * * * означает 0-ю минуту 6-го часа каждый день. Каждое ключевое слово проходит через обёртку с повторными попытками, неудачное ключевое слово записывается в журнал и пропускается, а не прерывает запуск, а 3-секундная пауза между ключевыми словами поддерживает разумный темп. Оставьте этот процесс запущенным (под менеджером процессов вроде pm2 или сервисом systemd в production) и он будет собирать свежий снимок каждое утро без какого-либо дополнительного участия с вашей стороны. Если вы предпочитаете не держать Node-процесс активным, уберите строку с cron и запускайте runJob из системного crontab или облачного планировщика, вызывающего node job.js по тому же выражению.
Шаг 5: Масштабирование с асинхронным Crawler и webhook
Синхронный цикл выше подходит для нескольких ключевых слов, но как только запуск охватывает сотни URL товаров, ожидание каждого запроса по очереди становится узким местом. Асинхронный Crawler создан для этого: вы отправляете ему URLs, он получает каждый за доверенным IP в фоне и доставляет готовую страницу на webhook, который вы разместили. Ваш планировщик перестаёт блокироваться на каждом запросе и просто ставит работу в очередь, а затем обрабатывает результаты по мере их поступления.
Сначала поставьте URLs в очередь. Асинхронный клиент принимает тот же токен и URL callback, указывающий на ваш webhook-эндпоинт.
const { CrawlingAPI } = require('crawlbase'); const api = new CrawlingAPI({ token: process.env.CRAWLBASE_TOKEN }); const productUrls = [ 'https://www.amazon.com/dp/B0CHX1W1XY', 'https://www.amazon.com/dp/B09G9FPHY6', ]; async function enqueue() { for (const url of productUrls) { const response = await api.getAsync(url, { callback: 'https://your-server.com/crawlbase-webhook', }); console.log(`Queued ${url} -> rid ${response.json.rid}`); } } enqueue();
Каждый вызов немедленно возвращает идентификатор запроса (rid), поэтому цикл завершается быстро независимо от количества поставленных в очередь URLs. Crawlbase выполняет получение данных в фоне и по мере завершения каждой страницы отправляет POST с готовым HTML на ваш коллбэк. Ваш webhook получает страницы, парсит их и сохраняет результаты, точно так же, как синхронный путь, но отдельно от постановки в очередь.
const express = require('express'); const cheerio = require('cheerio'); const app = express(); app.use(express.text({ type: '*/*', limit: '5mb' })); app.post('/crawlbase-webhook', (req, res) => { const $ = cheerio.load(req.body); const title = $('#productTitle').text().trim(); const price = $('.a-price .a-offscreen').first().text().trim(); if (title) saveRun([{ title, price: price || null }]); res.sendStatus(200); }); app.listen(3000, () => console.log('Webhook listening on 3000'));
URL коллбэка должен быть публично доступен, поэтому во время разработки откройте локальный сервер через туннель вроде ngrok и используйте этот HTTPS-адрес как значение callback. Всегда возвращайте 200 быстро, чтобы Crawlbase знал, что страница получена; парсинг и сохранение выполняйте либо перед ответом, либо в фоновой задаче. Для более глубокого изучения этого паттерна смотрите руководство о том, как извлекать данные с помощью Crawlbase Crawler, где асинхронная очередь и коллбэки разобраны подробно.
Как выглядят результаты
Каждый запуск записывает один JSON-файл в директорию data/ с временной меткой времени сбора. Структура одинакова независимо от того, пришли ли записи из синхронного цикла или асинхронного webhook, так что всё нижестоящее читает один формат.
{ "scrapedAt": "2026-06-11T06:00:04.812Z", "count": 2, "items": [ { "asin": "B0CHX1W1XY", "title": "Wireless Over-Ear Headphones, 40H Playtime", "price": "$59.99", "rating": "4.5 out of 5 stars", "reviews": "2,184", "productUrl": "https://www.amazon.com/dp/B0CHX1W1XY", "keyword": "wireless headphones" }, { "asin": "B09G9FPHY6", "title": "Compact Mechanical Keyboard, Hot-Swappable", "price": "$45.99", "rating": "4.4 out of 5 stars", "reviews": "1,073", "productUrl": "https://www.amazon.com/dp/B09G9FPHY6", "keyword": "mechanical keyboard" } ] }
Имея такую историю запусков, автоматизация начинает окупаться: загрузите любые два файла запусков, сопоставьте элементы по ASIN и получите ряд данных «цена во времени» для построения графика или настройки оповещений. То же хранилище питает трекер бестселлеров или уведомитель об изменении наличия без каких-либо изменений в самом скрапере.
Как избежать блокировки
Даже при обработке рендеринга и ротации через Crawling API запланированное задание, выполняемое без надзора, нуждается в привычках, которые поддерживают его работоспособность неделями, а не только в ходе одного хорошего запуска.
- Регулируйте расписание, а не только цикл. Запуск каждые несколько минут круглосуточно абсолютно не похож на поведение человека и быстро расходует кредиты. Ежедневного или почасового ритма достаточно для отслеживания цен и рейтингов, и это минимизирует ваш след.
- Позвольте ротации делать своё дело. Crawling API распределяет запросы по множеству жилых IP, чтобы ни один из них не превышал лимит. Если вы когда-нибудь будете создавать собственный стек, именно это нужно реализовать правильно, и наше руководство о том, как парсить сайты без блокировок, охватывает полный сценарий.
- Следите за кодами статуса в журналах. Запланированный запуск, который начинает возвращать ответы не с кодом 200, сигнализирует об изменениях. Поскольку задание журналирует каждый сбой, а обёртка с повторными попытками делает паузу, вы получаете бумажный след вместо молчаливой дыры в данных.
Законен ли автоматизированный парсинг Amazon?
Допустимость парсинга Amazon зависит от условий использования сервиса, вашей юрисдикции и того, как вы применяете данные. Условия Amazon ограничивают автоматизированный доступ, поэтому парсинг может нарушать их независимо от аккуратности вашего инструментария. Ни один из приведённых здесь кодов это не меняет; он лишь делает техническую часть рабочей. Ознакомьтесь с Условиями использования Amazon и его файлом robots.txt и рассматривайте оба документа как границу того, что вы собираете.
Несколько правил, которых стоит придерживаться. Собирайте только публичные данные о товарах: название, цену, рейтинг, количество отзывов, ASIN и ссылку на товар, которые любой желающий видит без аккаунта. Соблюдайте ожидания Amazon в отношении частоты запросов и держите запланированный объём на уровне, при котором вы не нагружаете серверы, именно для этого в данном руководстве важны ритм cron и регулирование. Не трогайте персональные данные, в том числе связанные с идентифицируемыми рецензентами помимо публичного текста отзыва на странице. Если вы планируете коммерческое использование данных, получите разрешение или лицензионное соглашение, а не рассчитывайте на то, что молчание равнозначно согласию.
Для объёмного или коммерческого использования Amazon предлагает официальные пути, включая Product Advertising API и Selling Partner API для продавцов, и это правильные инструменты, когда вам нужны большие объёмы, гарантированная структура или коммерческие права. Это руководство намеренно ограничено публичными страницами товаров и поиска, поскольку именно такая область делает работу защищённой. Здесь не рассматривается ничего за авторизацией, данных покупателей или продавцов, истории заказов, личных сообщений или попыток обойти аутентификацию. Если вашему проекту нужно больше, чем публичные данные, официальные API Amazon или соглашение о данных, правильный путь, а не более изощрённый скрапер или более быстрое расписание.
Ключевые выводы
- Автоматизация делает данные ценными. Разовый парсинг, это снимок; запланированный даёт изменения цен, рейтингов и наличия во времени.
-
Crawling API обрабатывает рендеринг и ротацию. Вы опираетесь на карточки Amazon с
data-asinи извлекаете цену, рейтинг и отзывы с помощью cheerio, пока API занимается блокировками и IP. - Повторные попытки и регулирование поддерживают задание без надзора. Обёртка с backoff восстанавливается после временных сбоев, а пропущенное ключевое слово никогда не убивает весь запуск.
-
Cron делает это автономным.
node-cronили системный планировщик запускает задание по фиксированному выражению, и каждый запуск сохраняется как JSON-файл с временной меткой для сравнения. - Асинхронный Crawler масштабирует это. Для крупных пакетов ставьте URLs в очередь с webhook-коллбэком, чтобы получение происходило в фоне, а не блокировало ваш цикл.
Часто задаваемые вопросы
Как запланировать автоматический запуск скрапера Amazon?
Простейший путь внутри Node, node-cron, который запускает функцию по стандартному cron-выражению из вашего процесса. Напишите логику парсинга и сохранения как одну функцию, затем запланируйте её, например 0 6 * * * для 6:00 ежедневно. Если вы предпочитаете не держать Node-процесс активным, поместите ту же логику в скрипт и запускайте его из системного crontab или облачного планировщика по тому же выражению.
Когда использовать асинхронный Crawler вместо синхронных запросов?
Используйте асинхронный Crawler, когда запуск охватывает много URLs и ожидание каждого запроса по очереди становится узким местом. Вы ставите URLs в очередь с webhook-коллбэком, Crawlbase получает каждую страницу в фоне за доверенным IP и отправляет готовый HTML на ваш эндпоинт. Синхронные запросы проще и подходят для нескольких страниц за запуск.
Как обрабатывать сбои в задании парсинга без надзора?
Оберните каждый запрос в вспомогательный метод с повторными попытками и backoff, сдающийся после нескольких попыток, затем перехватывайте и записывайте в журнал сбой на уровне ключевого слова, чтобы один плохой запрос пропускал этот элемент, а не прерывал пакет. Журналируйте каждый статус не 200, чтобы запуск оставлял бумажный след. Ротация Crawling API уже предотвращает большинство блокировок, поэтому повторные попытки в основном покрывают временные сбои.
Нужен ли JS-токен для парсинга Amazon?
Зачастую нет. Многие страницы поиска и товаров Amazon нормально парсятся с обычным токеном, который расходует меньше кредитов. Начните с обычного токена и переходите на JavaScript (JS) токен только если нужное поле возвращается пустым из-за клиентского рендеринга. Использование более дешёвого токена там, где он работает, делает запланированное задание доступным на бесплатном тарифе.
Где хранить спарсенные результаты?
Для небольшого задания JSON-файл с временной меткой за запуск надёжен и легко сравнивается позднее для отслеживания изменений цен или рейтингов. По мере роста объёма переходите на базу данных, чтобы эффективно запрашивать данные по запускам. В любом случае сохраняйте стабильную структуру записи и проставляйте каждый запуск временем scrapedAt, чтобы последующее сравнение знало, какому моменту принадлежит значение.
Законно ли автоматизировать парсинг Amazon?
Автоматизация не меняет правил; она лишь повторяет тот же парсинг неоднократно, что повышает важность регулирования. Оставайтесь на публичных данных о товарах, соблюдайте Условия использования Amazon и robots.txt, держите запланированный объём умеренным и избегайте персональных данных и всего, что находится за авторизацией. Для объёмного или коммерческого повторного использования официальный Product Advertising или Selling Partner API Amazon, санкционированный путь.
Обходите любой сайт в масштабе, без борьбы с инфраструктурой.
Crawlbase берёт на себя прокси, отпечатки и CAPTCHA, чтобы ваша команда выпускала конвейеры данных вместо поддержки обвязки краулинга. 1 000 запросов бесплатно, без карты.
