- Move debug/test scripts from src/scripts/ to experiments/ - Remove test-detail-endpoint from package.json - Delete temp-product-page.html - Move E2E_GUIDE.md to docs/ - Add experiments/README.md with documentation - Keep only production scripts in src/scripts/ - Clean up tsconfig.json exclude list (experiments are now outside src/) Co-Authored-By: Claude <noreply@anthropic.com>
150 lines
5.1 KiB
TypeScript
150 lines
5.1 KiB
TypeScript
import 'dotenv/config';
|
||
import { chromium } from 'playwright';
|
||
import axios from 'axios';
|
||
import { Logger } from '../utils/logger.js';
|
||
|
||
async function findDetailApiViaDirectRequest() {
|
||
Logger.info('=== МЕТОД 1: Прямой GET запрос к API ===\n');
|
||
|
||
const productId = '1000233138';
|
||
const storeCode = process.env.MAGNIT_STORE_CODE || '992301';
|
||
|
||
// Сначала получим cookies через Playwright
|
||
const browser = await chromium.launch({ headless: true });
|
||
const context = await browser.newContext();
|
||
const page = await context.newPage();
|
||
|
||
await page.goto('https://magnit.ru/', { waitUntil: 'domcontentloaded' });
|
||
const cookies = await context.cookies();
|
||
const cookieStr = cookies.map(c => `${c.name}=${c.value}`).join('; ');
|
||
|
||
const mgUdiCookie = cookies.find(c => c.name === 'mg_udi');
|
||
const deviceId = mgUdiCookie?.value || '';
|
||
|
||
await browser.close();
|
||
|
||
// Теперь пробуем разные endpoints
|
||
const httpClient = axios.create({
|
||
baseURL: 'https://magnit.ru',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Accept': '*/*',
|
||
'Cookie': cookieStr,
|
||
'x-device-id': deviceId,
|
||
'x-client-name': 'magnit',
|
||
'x-device-platform': 'Web',
|
||
'x-new-magnit': 'true',
|
||
},
|
||
});
|
||
|
||
const endpoints = [
|
||
`/webgate/v2/goods/${productId}?storeCode=${storeCode}&storeType=6`,
|
||
`/webgate/v2/goods/${productId}?shopCode=${storeCode}&shopType=6`,
|
||
`/webgate/v2/products/${productId}?storeCode=${storeCode}`,
|
||
`/webgate/v2/catalog/product/${productId}?storeCode=${storeCode}`,
|
||
];
|
||
|
||
for (const endpoint of endpoints) {
|
||
try {
|
||
Logger.info(`Пробую: GET ${endpoint}`);
|
||
const response = await httpClient.get(endpoint);
|
||
Logger.info(`✅ Status: ${response.status}`);
|
||
if (response.data) {
|
||
const json = JSON.stringify(response.data);
|
||
if (json.length < 2000) {
|
||
Logger.info(`Response: ${json}`);
|
||
} else {
|
||
Logger.info(`Response (preview): ${json.substring(0, 500)}...`);
|
||
}
|
||
}
|
||
break; // Если успешно, выходим
|
||
} catch (error: any) {
|
||
if (error.response?.status === 404) {
|
||
Logger.info(` ❌ 404 Not Found`);
|
||
} else if (error.response?.status === 403) {
|
||
Logger.info(` ❌ 403 Forbidden`);
|
||
} else {
|
||
Logger.info(` ❌ ${error.message}`);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
async function extractFromSSR() {
|
||
Logger.info('\n=== МЕТОД 2: Извлечение данных из SSR HTML ===\n');
|
||
|
||
const browser = await chromium.launch({ headless: true });
|
||
const context = await browser.newContext();
|
||
const page = await context.newPage();
|
||
|
||
const productUrl = 'https://magnit.ru/product/1000233138-podguzniki_la_fresh_dlya_vzroslykh_l_10sht?shopCode=992301&shopType=6';
|
||
|
||
Logger.info(`Загружаю страницу (без networkidle): ${productUrl}`);
|
||
|
||
try {
|
||
await page.goto(productUrl, {
|
||
waitUntil: 'domcontentloaded',
|
||
timeout: 15000,
|
||
});
|
||
|
||
// Ждем немного для рендеринга
|
||
await page.waitForTimeout(2000);
|
||
|
||
// Проверяем данные в HTML
|
||
const productData = await page.evaluate(() => {
|
||
// Ищем данные в window.__NUXT__
|
||
if ((window as any).__NUXT__) {
|
||
const nuxtData = (window as any).__NUXT__;
|
||
return {
|
||
source: '__NUXT__',
|
||
keys: Object.keys(nuxtData),
|
||
// Проверяем ключи с данными о товаре
|
||
data: nuxtData.data || nuxtData.pinia || null,
|
||
};
|
||
}
|
||
|
||
// Ищем JSON в скриптах
|
||
const scripts = Array.from(document.querySelectorAll('script[type="application/json"]'));
|
||
for (const script of scripts) {
|
||
try {
|
||
const json = JSON.parse(script.textContent || '');
|
||
if (json.product || json.goods || json.data?.product) {
|
||
return { source: 'application/json script', data: json };
|
||
}
|
||
} catch (e) {}
|
||
}
|
||
|
||
return { found: false };
|
||
});
|
||
|
||
if (productData.source) {
|
||
Logger.info(`✅ Данные найдены в: ${productData.source}`);
|
||
Logger.info(`Ключи: ${JSON.stringify(productData.keys || Object.keys(productData.data || {}))}`);
|
||
if (productData.data) {
|
||
Logger.info(`Данные (превью): ${JSON.stringify(productData.data).substring(0, 1000)}...`);
|
||
}
|
||
} else {
|
||
Logger.info(`❌ Данные не найдены`);
|
||
}
|
||
|
||
// Также сохраним HTML для анализа
|
||
const html = await page.content();
|
||
Logger.info(`\nHTML размер: ${html.length} символов`);
|
||
Logger.info(`HTML содержит "brand": ${html.includes('"brand"')} раз`);
|
||
Logger.info(`HTML содержит "description": ${html.includes('"description"')} раз`);
|
||
Logger.info(`HTML содержит "weight": ${html.includes('"weight"')} раз`);
|
||
|
||
} catch (error) {
|
||
Logger.error(`Ошибка: ${error}`);
|
||
} finally {
|
||
await browser.close();
|
||
}
|
||
}
|
||
|
||
async function main() {
|
||
await findDetailApiViaDirectRequest();
|
||
await extractFromSSR();
|
||
}
|
||
|
||
main();
|