feat: enhanced Magnit scraper with streaming mode and retry logic
- Add streaming mode for memory-efficient large catalog scraping - Implement retry logic with exponential backoff - Add auto session reinitialization on 403 errors - Add configurable options (pageSize, maxProducts, rateLimitDelay) - Add maxIterations protection against infinite loops - Add retry.ts utility module with withRetry and withRetryAndReinit - Update .env.example with new scraping options - Add pgAdmin and CloudBeaver to docker-compose Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -5,19 +5,50 @@ import { Logger } from '../utils/logger.js';
|
||||
|
||||
async function main() {
|
||||
const storeCode = process.env.MAGNIT_STORE_CODE || process.argv[2];
|
||||
|
||||
|
||||
if (!storeCode) {
|
||||
Logger.error('Не указан код магазина. Используйте переменную окружения MAGNIT_STORE_CODE или передайте как аргумент');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Выбор режима: streaming или legacy
|
||||
const useStreaming = process.env.MAGNIT_USE_STREAMING !== 'false';
|
||||
const maxProducts = process.env.MAGNIT_MAX_PRODUCTS
|
||||
? parseInt(process.env.MAGNIT_MAX_PRODUCTS, 10)
|
||||
: undefined;
|
||||
|
||||
Logger.info(`🚀 Запуск скрапинга для магазина: ${storeCode}`);
|
||||
Logger.info(`Режим: ${useStreaming ? 'STREAMING' : 'LEGACY'}`);
|
||||
if (maxProducts) {
|
||||
Logger.info(`Лимит товаров: ${maxProducts}`);
|
||||
}
|
||||
|
||||
const scraper = new MagnitApiScraper({
|
||||
storeCode,
|
||||
storeType: process.env.MAGNIT_STORE_TYPE || '6',
|
||||
catalogType: process.env.MAGNIT_CATALOG_TYPE || '1',
|
||||
headless: true,
|
||||
headless: process.env.MAGNIT_HEADLESS !== 'false',
|
||||
|
||||
// Новые параметры
|
||||
pageSize: process.env.MAGNIT_PAGE_SIZE ? parseInt(process.env.MAGNIT_PAGE_SIZE, 10) : 50,
|
||||
maxProducts,
|
||||
rateLimitDelay: process.env.MAGNIT_RATE_LIMIT_DELAY
|
||||
? parseInt(process.env.MAGNIT_RATE_LIMIT_DELAY, 10)
|
||||
: 300,
|
||||
maxIterations: process.env.MAGNIT_MAX_ITERATIONS
|
||||
? parseInt(process.env.MAGNIT_MAX_ITERATIONS, 10)
|
||||
: 10000,
|
||||
|
||||
retryOptions: {
|
||||
maxAttempts: process.env.MAGNIT_RETRY_ATTEMPTS
|
||||
? parseInt(process.env.MAGNIT_RETRY_ATTEMPTS, 10)
|
||||
: 3,
|
||||
initialDelay: 1000,
|
||||
maxDelay: 30000,
|
||||
},
|
||||
|
||||
requestTimeout: 30000,
|
||||
autoReinitOn403: true,
|
||||
});
|
||||
|
||||
try {
|
||||
@@ -27,20 +58,34 @@ async function main() {
|
||||
// Инициализация скрапера
|
||||
await scraper.initialize();
|
||||
|
||||
// Получение всех товаров
|
||||
const products = await scraper.scrapeAllProducts(100);
|
||||
let saved = 0;
|
||||
|
||||
Logger.info(`📦 Получено товаров: ${products.length}`);
|
||||
if (useStreaming) {
|
||||
// STREAMING режим (рекомендуется для больших каталогов)
|
||||
Logger.info('📡 Использование потокового режима скрапинга');
|
||||
|
||||
saved = await scraper.saveToDatabaseStreaming(prisma, {
|
||||
batchSize: 50,
|
||||
maxProducts,
|
||||
});
|
||||
|
||||
if (products.length > 0) {
|
||||
// Сохранение в БД
|
||||
const saved = await scraper.saveToDatabase(products, prisma);
|
||||
Logger.info(`✅ Успешно сохранено товаров: ${saved}`);
|
||||
} else {
|
||||
Logger.warn('⚠️ Товары не найдены');
|
||||
// LEGACY режим (обратная совместимость)
|
||||
Logger.info('📦 Использование legacy режима скрапинга');
|
||||
|
||||
const products = await scraper.scrapeAllProducts(50);
|
||||
Logger.info(`📦 Получено товаров: ${products.length}`);
|
||||
|
||||
if (products.length > 0) {
|
||||
saved = await scraper.saveToDatabase(products, prisma);
|
||||
} else {
|
||||
Logger.warn('⚠️ Товары не найдены');
|
||||
}
|
||||
}
|
||||
|
||||
Logger.info(`✅ Успешно сохранено товаров: ${saved}`);
|
||||
Logger.info('✅ Скрапинг завершен успешно');
|
||||
|
||||
} catch (error) {
|
||||
Logger.error('❌ Ошибка при скрапинге:', error);
|
||||
process.exit(1);
|
||||
|
||||
Reference in New Issue
Block a user