feat: add product detail enrichment for Magnit products
- Add isDetailsFetched field to Product model - Add fetchProductDetails() and fetchProductObjectInfo() methods to MagnitApiScraper - Add ProductParser methods for detail parsing - Add ProductService methods: getProductsNeedingDetails(), updateProductDetails(), markAsDetailsFetched() - Add enrich-product-details.ts script with statistics tracking - Update package.json with "enrich" script command - Add E2E_GUIDE.md documentation - Exclude debug scripts from tsconfig type-check (temporary) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { ProductItem } from '../../scrapers/api/magnit/types.js';
|
||||
import { ProductItem, ProductDetailsResponse, ObjectInfo } from '../../scrapers/api/magnit/types.js';
|
||||
import { CreateProductData } from '../product/ProductService.js';
|
||||
|
||||
export class ProductParser {
|
||||
@@ -80,5 +80,113 @@ export class ProductParser {
|
||||
return this.parseProductItem(item, storeId, categoryId);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Парсинг деталей товара из ProductDetailsResponse
|
||||
* Извлекает бренд, описание, вес, единицу измерения из массива details
|
||||
*/
|
||||
static parseProductDetails(detailsResponse: ProductDetailsResponse): {
|
||||
brand?: string;
|
||||
description?: string;
|
||||
weight?: string;
|
||||
unit?: string;
|
||||
categoryId?: number;
|
||||
} {
|
||||
const result: {
|
||||
brand?: string;
|
||||
description?: string;
|
||||
weight?: string;
|
||||
unit?: string;
|
||||
categoryId?: number;
|
||||
} = {};
|
||||
|
||||
// Получаем первую категорию из массива
|
||||
if (detailsResponse.categories && detailsResponse.categories.length > 0) {
|
||||
result.categoryId = detailsResponse.categories[0];
|
||||
}
|
||||
|
||||
// Парсим массив деталей для извлечения полей
|
||||
for (const detail of detailsResponse.details) {
|
||||
const name = detail.name;
|
||||
const nameLower = detail.name.toLowerCase();
|
||||
|
||||
// Бренд - проверяем и русское и английское название
|
||||
if (name === 'Бренд' || nameLower === 'brand') {
|
||||
// Игнорируем "Различные бренды"
|
||||
if (detail.value && !detail.value.includes('Различные бренды')) {
|
||||
result.brand = detail.value;
|
||||
}
|
||||
}
|
||||
|
||||
// Описание товара
|
||||
else if (name === 'Описание товара' || nameLower.includes('описание')) {
|
||||
if (detail.value) {
|
||||
result.description = detail.value;
|
||||
}
|
||||
}
|
||||
|
||||
// Вес - может быть на русском
|
||||
else if (nameLower.includes('вес') || nameLower === 'weight') {
|
||||
if (detail.value) {
|
||||
result.weight = detail.value;
|
||||
}
|
||||
}
|
||||
|
||||
// Единица измерения - может быть на русском
|
||||
else if (name === 'Единица измерения' || nameLower.includes('единица') || nameLower === 'unit') {
|
||||
if (detail.value) {
|
||||
result.unit = detail.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Парсинг ObjectInfo для получения рейтингов и описания
|
||||
*/
|
||||
static parseObjectInfo(objectInfo: ObjectInfo): {
|
||||
description?: string;
|
||||
rating?: number;
|
||||
scoresCount?: number;
|
||||
commentsCount?: number;
|
||||
imageUrl?: string;
|
||||
} {
|
||||
const result: {
|
||||
description?: string;
|
||||
rating?: number;
|
||||
scoresCount?: number;
|
||||
commentsCount?: number;
|
||||
imageUrl?: string;
|
||||
} = {};
|
||||
|
||||
// Описание из object_info (если есть)
|
||||
if (objectInfo.description) {
|
||||
result.description = objectInfo.description;
|
||||
}
|
||||
|
||||
// Рейтинг
|
||||
if (objectInfo.average_rating !== undefined) {
|
||||
result.rating = objectInfo.average_rating;
|
||||
}
|
||||
|
||||
// Количество оценок
|
||||
if (objectInfo.count_ratings !== undefined) {
|
||||
result.scoresCount = objectInfo.count_ratings;
|
||||
}
|
||||
|
||||
// Количество отзывов
|
||||
if (objectInfo.count_reviews !== undefined) {
|
||||
result.commentsCount = objectInfo.count_reviews;
|
||||
}
|
||||
|
||||
// URL изображения (если есть)
|
||||
if (objectInfo.url) {
|
||||
result.imageUrl = objectInfo.url;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user