Files
scan-sfera/public/test-parser.html
2025-07-19 17:56:06 +03:00

419 lines
14 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Тест Парсера Wildberries - ОБНОВЛЕНО</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
.container {
background: white;
border-radius: 12px;
padding: 30px;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
}
.header {
text-align: center;
margin-bottom: 30px;
}
.header h1 {
color: #2d3748;
margin-bottom: 10px;
}
.status-badge {
display: inline-block;
background: #48bb78;
color: white;
padding: 8px 16px;
border-radius: 20px;
font-size: 14px;
font-weight: 600;
}
.update-info {
background: #e6fffa;
border: 2px solid #48bb78;
border-radius: 8px;
padding: 20px;
margin-bottom: 30px;
}
.update-info h3 {
color: #2d3748;
margin-top: 0;
}
.update-info ul {
color: #4a5568;
line-height: 1.6;
}
.test-section {
background: #f7fafc;
border-radius: 8px;
padding: 25px;
margin-bottom: 25px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: #2d3748;
}
input[type="text"] {
width: 100%;
padding: 12px;
border: 2px solid #e2e8f0;
border-radius: 6px;
font-size: 16px;
box-sizing: border-box;
}
.preset-buttons {
display: flex;
gap: 10px;
flex-wrap: wrap;
margin-top: 10px;
}
.preset-btn {
background: #667eea;
color: white;
border: none;
padding: 8px 16px;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
transition: background 0.2s;
}
.preset-btn:hover {
background: #5a67d8;
}
.test-btn {
background: #48bb78;
color: white;
border: none;
padding: 15px 30px;
border-radius: 8px;
font-size: 18px;
font-weight: 600;
cursor: pointer;
width: 100%;
transition: background 0.2s;
}
.test-btn:hover:not(:disabled) {
background: #38a169;
}
.test-btn:disabled {
background: #a0aec0;
cursor: not-allowed;
}
.loading {
display: none;
text-align: center;
margin: 20px 0;
color: #4a5568;
}
.loading.active {
display: block;
}
.spinner {
display: inline-block;
width: 20px;
height: 20px;
border: 3px solid #e2e8f0;
border-radius: 50%;
border-top-color: #667eea;
animation: spin 1s ease-in-out infinite;
margin-right: 10px;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.results {
display: none;
margin-top: 30px;
}
.results.active {
display: block;
}
.result-header {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.status-icon {
font-size: 24px;
margin-right: 10px;
}
.product-card {
background: white;
border: 2px solid #e2e8f0;
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
}
.product-image {
width: 100px;
height: 100px;
object-fit: cover;
border-radius: 8px;
margin-right: 15px;
}
.product-info {
display: flex;
align-items: flex-start;
}
.product-details h3 {
margin: 0 0 10px 0;
color: #2d3748;
}
.positions-table {
width: 100%;
border-collapse: collapse;
background: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.positions-table th,
.positions-table td {
padding: 15px;
text-align: left;
border-bottom: 1px solid #e2e8f0;
}
.positions-table th {
background: #4a5568;
color: white;
font-weight: 600;
}
.position-found {
color: #48bb78;
font-weight: 600;
}
.position-not-found {
color: #f56565;
font-weight: 600;
}
.error {
background: #fed7d7;
border: 2px solid #f56565;
color: #c53030;
padding: 15px;
border-radius: 8px;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🎯 Тест Парсера Wildberries</h1>
<span class="status-badge">✅ РАБОТАЕТ</span>
</div>
<div class="update-info">
<h3>🚀 Парсер обновлен и работает!</h3>
<ul>
<li><strong>Решена проблема блокировки:</strong> Добавлены продвинутые методы обхода защиты Wildberries</li>
<li><strong>Улучшенная маскировка:</strong> Парсер теперь имитирует реальное поведение пользователя</li>
<li><strong>API поиск:</strong> Добавлен резервный поиск через внутренние API</li>
<li><strong>Стабильная работа:</strong> Тестирование показало успешное нахождение товаров</li>
<li><strong>Корректная обработка:</strong> Правильно обрабатывает случаи "товар не найден"</li>
</ul>
</div>
<div class="test-section">
<h2>🧪 Протестировать парсер</h2>
<div class="form-group">
<label for="query">Поисковый запрос:</label>
<input type="text" id="query" value="лабубу" placeholder="Введите поисковый запрос">
<div class="preset-buttons">
<button class="preset-btn" onclick="setPreset('лабубу', '447020075')">Лабубу (работает)</button>
<button class="preset-btn" onclick="setPreset('плюшевая игрушка', '197761909')">Плюшевая игрушка (работает)</button>
<button class="preset-btn" onclick="setPreset('игрушка', '123456789')">Тест "не найдено"</button>
</div>
</div>
<div class="form-group">
<label for="article">Артикул товара:</label>
<input type="text" id="article" value="447020075" placeholder="Введите артикул">
</div>
<button class="test-btn" onclick="testParser()" id="testBtn">
🔍 Запустить тест парсера
</button>
<div class="loading" id="loading">
<div class="spinner"></div>
Парсинг в процессе... Это может занять до 1 минуты
</div>
</div>
<div class="results" id="results">
<div class="result-header">
<span class="status-icon" id="statusIcon"></span>
<h2 id="resultTitle"></h2>
</div>
<div id="resultContent"></div>
</div>
</div>
<script>
function setPreset(query, article) {
document.getElementById('query').value = query;
document.getElementById('article').value = article;
}
async function testParser() {
const query = document.getElementById('query').value.trim();
const article = document.getElementById('article').value.trim();
if (!query || !article) {
alert('Пожалуйста, заполните все поля');
return;
}
const testBtn = document.getElementById('testBtn');
const loading = document.getElementById('loading');
const results = document.getElementById('results');
// Показываем индикатор загрузки
testBtn.disabled = true;
loading.classList.add('active');
results.classList.remove('active');
try {
const response = await fetch('/api/test-parser', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: query,
myArticleId: article
})
});
const data = await response.json();
if (data.success) {
showResults(true, data.data, data.message);
} else {
showResults(false, null, data.error || 'Произошла ошибка');
}
} catch (error) {
showResults(false, null, 'Ошибка соединения: ' + error.message);
} finally {
testBtn.disabled = false;
loading.classList.remove('active');
}
}
function showResults(success, data, message) {
const results = document.getElementById('results');
const statusIcon = document.getElementById('statusIcon');
const resultTitle = document.getElementById('resultTitle');
const resultContent = document.getElementById('resultContent');
if (success && data) {
statusIcon.textContent = '✅';
resultTitle.textContent = 'Парсинг выполнен успешно!';
const product = data.product;
const positions = data.positions;
const foundPositions = positions.filter(p => p.position !== null);
const isFound = foundPositions.length > 0;
resultContent.innerHTML = `
<div class="product-card">
<div class="product-info">
<img src="${product.imageUrl}" alt="${product.name}" class="product-image" onerror="this.src='/images/no-image.svg'">
<div class="product-details">
<h3>${product.name}</h3>
<p><strong>Бренд:</strong> ${product.brand}</p>
<p><strong>Цена:</strong> ${product.price} ₽</p>
<p><strong>Артикул:</strong> ${product.article}</p>
<p><strong>Статус:</strong> ${isFound ? '<span class="position-found">Найден в поиске</span>' : '<span class="position-not-found">Не найден в поиске</span>'}</p>
</div>
</div>
</div>
<h3>Позиции по городам:</h3>
<table class="positions-table">
<thead>
<tr>
<th>Город</th>
<th>Код</th>
<th>Позиция</th>
<th>Статус</th>
</tr>
</thead>
<tbody>
${positions.map(pos => `
<tr>
<td>${pos.city}</td>
<td>${pos.cityCode}</td>
<td>${pos.position || '—'}</td>
<td>${pos.position ? '<span class="position-found">Найден</span>' : '<span class="position-not-found">Не найден</span>'}</td>
</tr>
`).join('')}
</tbody>
</table>
<p style="margin-top: 20px; color: #4a5568; font-style: italic;">${message}</p>
`;
} else {
statusIcon.textContent = '❌';
resultTitle.textContent = 'Ошибка парсинга';
resultContent.innerHTML = `<div class="error">${message}</div>`;
}
results.classList.add('active');
}
</script>
</body>
</html>