Ozon Scraper

Быстро прокручивает страницу категории Ozon и копирует результаты в буфер обмена.

Você precisará instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Você precisará instalar uma extensão como o Tampermonkey para instalar este script.

Você precisará instalar um gerenciador de scripts de usuário para instalar este script.

(Eu já tenho um gerenciador de scripts de usuário, me deixe instalá-lo!)

Advertisement:

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

(Eu já possuo um gerenciador de estilos de usuário, me deixar fazer a instalação!)

Advertisement:

// ==UserScript==
// @name         Ozon Scraper
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  Быстро прокручивает страницу категории Ozon и копирует результаты в буфер обмена.
// @author       torch
// @match        https://www.ozon.ru/*
// @grant        GM_setClipboard
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    // Создание контейнера для панели управления
    const panel = document.createElement('div');
    panel.id = 'ozon-scraper-panel';
    panel.style.cssText = `
        position: fixed;
        bottom: 24px;
        right: 24px;
        z-index: 999999;
        background: rgba(20, 20, 20, 0.85);
        backdrop-filter: blur(12px);
        -webkit-backdrop-filter: blur(12px);
        border: 1px solid rgba(255, 255, 255, 0.12);
        border-radius: 16px;
        padding: 16px;
        color: #f3f4f6;
        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
        box-shadow: 0 12px 40px rgba(0, 0, 0, 0.6);
        width: 280px;
        box-sizing: border-box;
        transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    `;

    panel.innerHTML = `
        <div style="font-weight: 600; margin-bottom: 12px; font-size: 14px; display: flex; justify-content: space-between; align-items: center; letter-spacing: -0.01em;">
            <span>Ozon Scraper (Fast)</span>
            <span id="scraper-status" style="font-size: 10px; background: #ef4444; color: #fff; padding: 3px 8px; border-radius: 20px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;">Остановлен</span>
        </div>
        <div style="font-size: 12px; margin-bottom: 16px; color: #9ca3af; display: flex; justify-content: space-between;">
            <span>Найдено товаров:</span>
            <span id="product-count" style="font-weight: 700; color: #10b981; font-size: 13px;">0</span>
        </div>
        <div style="display: flex; flex-direction: column; gap: 8px;">
            <button id="btn-toggle-scroll" style="background: #2563eb; color: white; border: none; padding: 10px; border-radius: 8px; cursor: pointer; font-weight: 600; font-size: 13px; transition: background 0.2s;">▶ Быстрая прокрутка</button>
            <button id="btn-copy-data" style="background: #10b981; color: #042f1a; border: none; padding: 10px; border-radius: 8px; cursor: pointer; font-weight: 600; font-size: 13px; transition: background 0.2s;">📋 Скопировать данные</button>
            <button id="btn-reset" style="background: transparent; color: #9ca3af; border: 1px solid #4b5563; padding: 8px; border-radius: 8px; cursor: pointer; font-size: 11px; transition: all 0.2s;">Сбросить счетчик</button>
        </div>
    `;
    document.body.appendChild(panel);

    // Переменные состояния
    let isScrolling = false;
    let scrollTimer = null;
    let lastCollectedCount = 0;
    let noNewItemsStreak = 0;
    const seenSkus = new Set();
    const collectedProducts = [];

    // Элементы интерфейса
    const statusBadge = document.getElementById('scraper-status');
    const countSpan = document.getElementById('product-count');
    const toggleBtn = document.getElementById('btn-toggle-scroll');
    const copyBtn = document.getElementById('btn-copy-data');
    const resetBtn = document.getElementById('btn-reset');

    // Функция парсинга карточек товаров
    function scanVisibleProducts() {
        const productLinks = document.querySelectorAll('a[href*="/product/"]');

        productLinks.forEach(link => {
            const href = link.getAttribute('href');
            if (!href) return;

            const skuMatch = href.match(/-(\d+)\/?(?:\?|$)/);
            const sku = skuMatch ? skuMatch[1] : href.split('?')[0];

            if (seenSkus.has(sku)) return;

            let cardContainer = link.closest('[data-index]') || link.closest('.tile-root') || link.parentElement;
            while (cardContainer && cardContainer !== document.body && !cardContainer.querySelector('img')) {
                cardContainer = cardContainer.parentElement;
            }

            if (!cardContainer) return;

            let name = "";
            const nameEl = cardContainer.querySelector('span[class*="tsBody500Medium"], a[href*="/product/"] span, span[class*="tsBody"]');
            if (nameEl) name = nameEl.innerText.trim();
            if (!name || name.length < 5) {
                name = link.innerText.trim();
            }

            if (!name || name.length < 4 || name.includes("₽") || name.includes("рейтинг")) return;

            let price = "N/A";
            const priceElements = Array.from(cardContainer.querySelectorAll('*')).filter(el => {
                return el.children.length === 0 && el.innerText && (el.innerText.includes('₽') || el.innerText.includes(' ₽'));
            });
            if (priceElements.length > 0) {
                price = priceElements[0].innerText.trim().replace(/\s+/g, ' ');
            }

            const cleanUrl = 'https://www.ozon.ru' + href.split('?')[0];
            seenSkus.add(sku);
            collectedProducts.push({ name, price, url: cleanUrl, sku });
        });

        countSpan.innerText = collectedProducts.length;
    }

    // Функция быстрой циклической прокрутки
    function scrollPageStep() {
        window.scrollBy(0, window.innerHeight * 0.85);
        scanVisibleProducts();

        if (collectedProducts.length === lastCollectedCount) {
            noNewItemsStreak++;
        } else {
            noNewItemsStreak = 0;
            lastCollectedCount = collectedProducts.length;
        }

        // Порог увеличен до 35 попыток (около 12 секунд ожидания при медленном интернете),
        // чтобы дать Ozon время на загрузку данных на высокой скорости прокрутки.
        if (noNewItemsStreak >= 35) {
            pauseScrolling();
            statusBadge.innerText = 'Завершено';
            statusBadge.style.background = '#10b981';
            statusBadge.style.color = '#fff';
            alert(`Сбор завершен. Уникальных товаров собрано: ${collectedProducts.length}`);
        }
    }

    function startScrolling() {
        isScrolling = true;
        toggleBtn.innerText = '⏸ Приостановить';
        toggleBtn.style.background = '#ef4444';
        statusBadge.innerText = 'Быстрый скролл';
        statusBadge.style.background = '#2563eb';

        // Быстрый интервал — 350 мс
        scrollTimer = setInterval(scrollPageStep, 350);
    }

    function pauseScrolling() {
        isScrolling = false;
        toggleBtn.innerText = '▶ Быстрая прокрутка';
        toggleBtn.style.background = '#2563eb';
        statusBadge.innerText = 'Остановлен';
        statusBadge.style.background = '#ef4444';
        if (scrollTimer) {
            clearInterval(scrollTimer);
            scrollTimer = null;
        }
    }

    // Обработчики кнопок
    toggleBtn.addEventListener('click', () => {
        if (isScrolling) {
            pauseScrolling();
        } else {
            startScrolling();
        }
    });

    copyBtn.addEventListener('click', () => {
        if (collectedProducts.length === 0) {
            alert("Нет данных для копирования. Пожалуйста, запустите прокрутку.");
            return;
        }

        let tsvOutput = "Название товара\tЦена\tСсылка на товар\tSKU\n";
        collectedProducts.forEach(p => {
            tsvOutput += `${p.name}\t${p.price}\t${p.url}\t${p.sku}\n`;
        });

        if (typeof GM_setClipboard !== 'undefined') {
            GM_setClipboard(tsvOutput);
            alert(`Данные (${collectedProducts.length} шт.) успешно скопированы! Откройте Excel или Google Таблицы и вставьте их через Ctrl+V.`);
        } else {
            navigator.clipboard.writeText(tsvOutput).then(() => {
                alert(`Данные (${collectedProducts.length} шт.) успешно скопированы!`);
            }).catch(err => {
                const fallbackArea = document.createElement('textarea');
                fallbackArea.value = tsvOutput;
                document.body.appendChild(fallbackArea);
                fallbackArea.select();
                document.execCommand('copy');
                document.body.removeChild(fallbackArea);
                alert(`Данные (${collectedProducts.length} шт.) скопированы (резервный метод).`);
            });
        }
    });

    resetBtn.addEventListener('click', () => {
        if (confirm("Вы действительно хотите очистить результаты?")) {
            seenSkus.clear();
            collectedProducts.length = 0;
            lastCollectedCount = 0;
            noNewItemsStreak = 0;
            countSpan.innerText = '0';
            if (!isScrolling) {
                statusBadge.innerText = 'Остановлен';
                statusBadge.style.background = '#ef4444';
            }
        }
    });

    scanVisibleProducts();
})();