// ==UserScript==
// @name         멀티 검색 엔진 웹 크롤러
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  여러 검색 엔진의 결과를 크롤링하여 데이터를 수집하고 UI에 표시합니다.
// @author       Your Name
// @match        https://www.google.com/*
// @match        https://yandex.com/*
// @match        https://www.bing.com/*
// @grant        GM_xmlhttpRequest
// @grant        GM_setClipboard
// @connect      *
// @require      https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    // 전역 변수
    let collectedData = [];
    let visitedUrls = new Set();
    let currentPage = 0;
    let isCrawling = false;
    let selectedEngine = 'Google'; // 기본 검색 엔진
    let totalPages = 0;
    let processedPages = 0;
    let searchQuery = '';
    let stopCrawling = false;

    // 검색 엔진별 설정
    const searchEngines = {
        'Google': {
            searchBoxSelector: 'input[name="q"]',
            searchButtonSelector: 'input[name="btnK"]',
            resultsSelector: 'div.g',
            siteNameSelector: 'h3',
            siteUrlSelector: 'a',
            siteDescriptionSelector: '.VwiC3b',
            nextPageSelector: '#pnnext',
        },
        'Yandex': {
            searchBoxSelector: 'input.input__control[name="text"]',
            searchButtonSelector: 'button.Button2_type_submit',
            resultsSelector: 'li.serp-item',
            siteNameSelector: 'a.link.organic__url',
            siteUrlSelector: 'a.link.organic__url',
            siteDescriptionSelector: 'div.text-container__text',
            nextPageSelector: 'a.link.pager__item_kind_next',
        },
        'Bing': {
            searchBoxSelector: 'input[name="q"]',
            searchButtonSelector: 'input[type="submit"]',
            resultsSelector: 'li.b_algo',
            siteNameSelector: 'h2',
            siteUrlSelector: 'h2 a',
            siteDescriptionSelector: '.b_caption p',
            nextPageSelector: 'a.sb_pagN',
        }
        // 추가 검색 엔진 설정 가능
    };

    // UI 생성 함수
    function createUI() {
        // UI 컨테이너 생성
        const container = document.createElement('div');
        container.id = 'crawler-container';
        container.style.position = 'fixed';
        container.style.top = '10px';
        container.style.right = '10px';
        container.style.width = '600px';
        container.style.height = '700px';
        container.style.backgroundColor = '#f9f9f9';
        container.style.border = '1px solid #ccc';
        container.style.zIndex = '10000';
        container.style.padding = '10px';
        container.style.overflowY = 'auto';
        container.style.boxShadow = '0 0 10px rgba(0,0,0,0.1)';
        container.style.fontFamily = 'Arial, sans-serif';

        // 탭 메뉴
        const tabMenu = document.createElement('div');
        tabMenu.style.display = 'flex';
        tabMenu.style.marginBottom = '10px';

        const tabs = ['📜 로그', '📊 데이터', '⚙️ 설정'];
        tabs.forEach((tabName, index) => {
            const tab = document.createElement('button');
            tab.textContent = tabName;
            tab.dataset.index = index;
            tab.style.flex = '1';
            tab.style.padding = '10px';
            tab.style.border = 'none';
            tab.style.backgroundColor = index === 0 ? '#ddd' : '#f9f9f9';
            tab.style.cursor = 'pointer';
            tab.style.transition = 'background-color 0.3s';
            tab.title = `${tabName} 탭 전환`;
            tab.addEventListener('click', () => switchTab(index));
            tab.addEventListener('mouseover', () => {
                tab.style.backgroundColor = '#ccc';
            });
            tab.addEventListener('mouseout', () => {
                tab.style.backgroundColor = index === 0 ? '#ddd' : '#f9f9f9';
            });
            tabMenu.appendChild(tab);
        });

        container.appendChild(tabMenu);

        // 탭 콘텐츠
        const tabContent = document.createElement('div');
        tabContent.id = 'tab-content';
        container.appendChild(tabContent);

        // 추가 기능: 크롤링 컨트롤 패널
        const controlPanel = document.createElement('div');
        controlPanel.style.marginBottom = '10px';
        controlPanel.style.borderTop = '1px solid #ccc';
        controlPanel.style.paddingTop = '10px';

        // 검색어 입력
        const searchInputLabel = document.createElement('label');
        searchInputLabel.textContent = '🔍 검색어: ';
        searchInputLabel.style.display = 'block';
        searchInputLabel.style.marginBottom = '5px';
        const searchInput = document.createElement('input');
        searchInput.type = 'text';
        searchInput.id = 'search-query';
        searchInput.style.width = '100%';
        searchInput.placeholder = '검색어를 입력하세요';
        searchInputLabel.appendChild(searchInput);
        controlPanel.appendChild(searchInputLabel);

        // 시작 버튼
        const startButton = document.createElement('button');
        startButton.textContent = '🚀 크롤링 시작';
        startButton.style.padding = '10px';
        startButton.style.marginRight = '10px';
        startButton.style.cursor = 'pointer';
        startButton.title = '크롤링을 시작합니다.';
        startButton.addEventListener('click', () => {
            const query = document.getElementById('search-query').value.trim();
            if (query) {
                searchQuery = query;
                startCrawling(query);
            } else {
                alert('검색어를 입력해주세요.');
            }
        });
        controlPanel.appendChild(startButton);

        // 중지 버튼
        const stopButton = document.createElement('button');
        stopButton.textContent = '⏹️ 크롤링 중지';
        stopButton.style.padding = '10px';
        stopButton.style.cursor = 'pointer';
        stopButton.title = '크롤링을 중지합니다.';
        stopButton.addEventListener('click', () => {
            if (isCrawling) {
                stopCrawling = true;
                log('크롤링 중지 요청됨.', 'warn');
            }
        });
        controlPanel.appendChild(stopButton);

        // 진행률 표시
        const progressContainer = document.createElement('div');
        progressContainer.style.marginTop = '10px';
        progressContainer.style.backgroundColor = '#e0e0e0';
        progressContainer.style.borderRadius = '5px';
        progressContainer.style.overflow = 'hidden';
        progressContainer.title = '크롤링 진행률';
        const progressBar = document.createElement('div');
        progressBar.id = 'progress-bar';
        progressBar.style.width = '0%';
        progressBar.style.height = '20px';
        progressBar.style.backgroundColor = '#76c7c0';
        progressContainer.appendChild(progressBar);
        controlPanel.appendChild(progressContainer);

        container.appendChild(controlPanel);

        document.body.appendChild(container);

        // 초기 탭
        renderLogs();
    }

    // 탭 전환 함수
    function switchTab(index) {
        const tabs = document.querySelectorAll('#crawler-container button');
        tabs.forEach((tab, i) => {
            tab.style.backgroundColor = i === index ? '#ddd' : '#f9f9f9';
        });

        switch(index) {
            case 0:
                renderLogs();
                break;
            case 1:
                renderData();
                break;
            case 2:
                renderSettings();
                break;
        }
    }

    // 로그 탭 렌더링
    function renderLogs() {
        const content = document.getElementById('tab-content');
        content.innerHTML = '';
        const logArea = document.createElement('textarea');
        logArea.id = 'log-area';
        logArea.style.width = '100%';
        logArea.style.height = '500px';
        logArea.readOnly = true;
        logArea.title = '진행 로그';
        content.appendChild(logArea);
    }

    // 데이터 탭 렌더링
    function renderData() {
        const content = document.getElementById('tab-content');
        content.innerHTML = '';

        // 검색 필드
        const searchField = document.createElement('input');
        searchField.type = 'text';
        searchField.id = 'data-search';
        searchField.placeholder = '데이터를 검색하세요';
        searchField.style.width = '100%';
        searchField.style.marginBottom = '10px';
        searchField.title = '데이터 검색 필드';
        searchField.addEventListener('input', filterTable);
        content.appendChild(searchField);

        // 데이터 테이블
        const table = document.createElement('table');
        table.id = 'data-table';
        table.style.width = '100%';
        table.style.borderCollapse = 'collapse';
        table.style.marginBottom = '10px';

        // 헤더
        const header = document.createElement('tr');
        ['사이트 이름', '주소', '설명', '분류', '텍스트 내용', 'HTML 내용'].forEach(text => {
            const th = document.createElement('th');
            th.textContent = text;
            th.style.border = '1px solid #ccc';
            th.style.padding = '5px';
            th.style.backgroundColor = '#f2f2f2';
            header.appendChild(th);
        });
        table.appendChild(header);

        // 데이터
        collectedData.forEach(item => {
            const row = document.createElement('tr');

            // 사이트 이름
            const nameTd = document.createElement('td');
            nameTd.textContent = item.name;
            nameTd.style.border = '1px solid #ccc';
            nameTd.style.padding = '5px';
            row.appendChild(nameTd);

            // 주소
            const urlTd = document.createElement('td');
            const urlLink = document.createElement('a');
            urlLink.href = item.url;
            urlLink.textContent = item.url;
            urlLink.target = '_blank';
            urlTd.appendChild(urlLink);
            urlTd.style.border = '1px solid #ccc';
            urlTd.style.padding = '5px';
            row.appendChild(urlTd);

            // 설명
            const descTd = document.createElement('td');
            descTd.textContent = item.description;
            descTd.style.border = '1px solid #ccc';
            descTd.style.padding = '5px';
            row.appendChild(descTd);

            // 분류
            const catTd = document.createElement('td');
            catTd.textContent = item.category;
            catTd.style.border = '1px solid #ccc';
            catTd.style.padding = '5px';
            row.appendChild(catTd);

            // 텍스트 내용
            const textTd = document.createElement('td');
            textTd.textContent = item.description;
            textTd.style.border = '1px solid #ccc';
            textTd.style.padding = '5px';
            row.appendChild(textTd);

            // HTML 내용 (모달 링크)
            const htmlTd = document.createElement('td');
            const htmlLink = document.createElement('a');
            htmlLink.href = '#';
            htmlLink.textContent = '보기';
            htmlLink.style.color = 'blue';
            htmlLink.style.textDecoration = 'underline';
            htmlLink.addEventListener('click', (e) => {
                e.preventDefault();
                showHTMLModal(item.htmlContent);
            });
            htmlTd.appendChild(htmlLink);
            htmlTd.style.border = '1px solid #ccc';
            htmlTd.style.padding = '5px';
            row.appendChild(htmlTd);

            table.appendChild(row);
        });

        content.appendChild(table);

        // 엑셀 다운로드 버튼
        const exportButton = document.createElement('button');
        exportButton.textContent = '📥 엑셀 다운로드';
        exportButton.style.padding = '10px';
        exportButton.style.cursor = 'pointer';
        exportButton.title = '데이터를 엑셀 파일로 다운로드';
        exportButton.addEventListener('click', exportToExcel);
        content.appendChild(exportButton);
    }

    // 설정 탭 렌더링
    function renderSettings() {
        const content = document.getElementById('tab-content');
        content.innerHTML = '';

        const settingsForm = document.createElement('form');

        // 검색 엔진 선택
        const engineLabel = document.createElement('label');
        engineLabel.textContent = '🔍 검색 엔진 선택: ';
        engineLabel.style.display = 'block';
        engineLabel.style.marginBottom = '5px';
        const engineSelect = document.createElement('select');
        engineSelect.id = 'search-engine';
        engineSelect.title = '크롤링에 사용할 검색 엔진을 선택합니다.';
        for (let engine in searchEngines) {
            const option = document.createElement('option');
            option.value = engine;
            option.textContent = engine;
            if (engine === selectedEngine) {
                option.selected = true;
            }
            engineSelect.appendChild(option);
        }
        engineLabel.appendChild(engineSelect);
        settingsForm.appendChild(engineLabel);
        settingsForm.appendChild(document.createElement('br'));

        // 블랙리스트 도메인
        const blacklistLabel = document.createElement('label');
        blacklistLabel.textContent = '🚫 블랙리스트 도메인 (comma separated): ';
        blacklistLabel.style.display = 'block';
        blacklistLabel.style.marginBottom = '5px';
        const blacklistInput = document.createElement('input');
        blacklistInput.type = 'text';
        blacklistInput.id = 'blacklist-domains';
        blacklistInput.style.width = '100%';
        blacklistInput.placeholder = '예: ads.example.com, spam.example.com';
        blacklistInput.title = '크롤링에서 제외할 도메인들을 쉼표로 구분하여 입력합니다.';
        blacklistLabel.appendChild(blacklistInput);
        settingsForm.appendChild(blacklistLabel);
        settingsForm.appendChild(document.createElement('br'));

        // 화이트리스트 도메인
        const whitelistLabel = document.createElement('label');
        whitelistLabel.textContent = '✅ 화이트리스트 도메인 (comma separated): ';
        whitelistLabel.style.display = 'block';
        whitelistLabel.style.marginBottom = '5px';
        const whitelistInput = document.createElement('input');
        whitelistInput.type = 'text';
        whitelistInput.id = 'whitelist-domains';
        whitelistInput.style.width = '100%';
        whitelistInput.placeholder = '예: edu.example.com, blog.example.com';
        whitelistInput.title = '크롤링에서 허용할 도메인들을 쉼표로 구분하여 입력합니다.';
        whitelistLabel.appendChild(whitelistInput);
        settingsForm.appendChild(whitelistLabel);
        settingsForm.appendChild(document.createElement('br'));

        // 저장 버튼
        const saveButton = document.createElement('button');
        saveButton.type = 'button';
        saveButton.textContent = '💾 설정 저장 (Ctrl+S)';
        saveButton.style.padding = '10px';
        saveButton.style.marginTop = '10px';
        saveButton.style.cursor = 'pointer';
        saveButton.title = '설정을 저장합니다.';
        saveButton.addEventListener('click', saveSettings);
        settingsForm.appendChild(saveButton);

        content.appendChild(settingsForm);
    }

    // 설정 저장 함수
    function saveSettings() {
        selectedEngine = document.getElementById('search-engine').value;
        const blacklist = document.getElementById('blacklist-domains').value.split(',').map(s => s.trim()).filter(s => s);
        const whitelist = document.getElementById('whitelist-domains').value.split(',').map(s => s.trim()).filter(s => s);
        localStorage.setItem('selectedEngine', selectedEngine);
        localStorage.setItem('blacklistDomains', JSON.stringify(blacklist));
        localStorage.setItem('whitelistDomains', JSON.stringify(whitelist));
        log(`설정이 저장되었습니다. 선택된 검색 엔진: ${selectedEngine}`);
    }

    // 설정 불러오기 함수
    function loadSettings() {
        selectedEngine = localStorage.getItem('selectedEngine') || 'Google';
        const blacklist = JSON.parse(localStorage.getItem('blacklistDomains')) || [];
        const whitelist = JSON.parse(localStorage.getItem('whitelistDomains')) || [];
        return { blacklist, whitelist };
    }

    // 로그 함수
    function log(message, type = 'info') {
        const logArea = document.getElementById('log-area');
        if (logArea) {
            logArea.value += `[${new Date().toLocaleTimeString()}] [${type.toUpperCase()}] ${message}\n`;
            logArea.scrollTop = logArea.scrollHeight;
        }
        switch(type) {
            case 'info':
                console.info(message);
                break;
            case 'warn':
                console.warn(message);
                break;
            case 'error':
                console.error(message);
                break;
            default:
                console.log(message);
        }
    }

    // 크롤링 시작 함수
    async function startCrawling(query) {
        if (isCrawling) {
            log('이미 크롤링이 진행 중입니다.', 'warn');
            return;
        }
        isCrawling = true;
        stopCrawling = false;
        collectedData = [];
        visitedUrls = new Set();
        currentPage = 1;
        processedPages = 0;
        log(`크롤링 시작: "${query}"`);

        // 설정 불러오기
        const settings = loadSettings();

        // 검색어 입력 및 검색 실행
        const engineConfig = searchEngines[selectedEngine];

        const searchInput = document.querySelector(engineConfig.searchBoxSelector);
        const searchButton = document.querySelector(engineConfig.searchButtonSelector);

        if (searchInput && searchButton) {
            searchInput.value = query;
            searchButton.click();
            waitForResults();
        } else {
            log('검색창이나 검색 버튼을 찾을 수 없습니다.', 'error');
            isCrawling = false;
        }
    }

    // 검색 결과 대기 및 처리
    function waitForResults() {
        const engineConfig = searchEngines[selectedEngine];
        const resultsSelector = engineConfig.resultsSelector;
        const interval = setInterval(() => {
            const results = document.querySelectorAll(resultsSelector);
            if (results.length > 0) {
                clearInterval(interval);
                log(`검색 결과 ${results.length}개 발견. 페이지 ${currentPage} 처리 시작.`);
                processResults(results);
            }
        }, 1000);
    }

    // 검색 결과 처리
    async function processResults(results) {
        const settings = loadSettings();
        const engineConfig = searchEngines[selectedEngine];
        totalPages = totalPages || estimateTotalPages(); // 추정된 총 페이지 수

        for (let result of results) {
            if (stopCrawling) {
                log('크롤링이 중지되었습니다.', 'warn');
                isCrawling = false;
                updateProgress();
                return;
            }

            // 사이트 이름, URL, 설명 추출
            let siteName = '';
            let siteUrl = '';
            let siteDescription = '';
            let htmlContent = '';

            try {
                siteName = result.querySelector(engineConfig.siteNameSelector)?.innerText || 'N/A';
                siteUrl = result.querySelector(engineConfig.siteUrlSelector)?.href || 'N/A';
                siteDescription = result.querySelector(engineConfig.siteDescriptionSelector)?.innerText || 'N/A';
                htmlContent = result.innerHTML || 'N/A';
            } catch (error) {
                log(`데이터 추출 실패: ${error}`, 'error');
                continue;
            }

            // 중복 검사
            if (visitedUrls.has(siteUrl)) {
                log(`중복된 URL 발견: ${siteUrl}`, 'warn');
                continue;
            }

            // 블랙리스트/화이트리스트 검사
            const domain = (new URL(siteUrl)).hostname;
            if (settings.whitelist.length > 0 && !settings.whitelist.includes(domain)) {
                log(`화이트리스트에 없는 도메인: ${domain}`, 'warn');
                continue;
            }
            if (settings.blacklist.includes(domain)) {
                log(`블랙리스트에 있는 도메인: ${domain}`, 'warn');
                continue;
            }

            visitedUrls.add(siteUrl);

            // 콘텐츠 품질 평가
            const qualityScore = evaluateContentQuality(siteDescription);

            // 자동 키워드 분류
            const category = classifyKeywords(siteDescription);

            collectedData.push({
                name: siteName,
                url: siteUrl,
                description: siteDescription,
                category: category,
                quality: qualityScore,
                htmlContent: htmlContent
            });

            log(`수집 완료: ${siteName} (${siteUrl})`);

            // 데이터 탭이 활성화되어 있다면 실시간 업데이트
            if (document.querySelector('#crawler-container button[data-index="1"][style*="background-color: #ddd"]')) {
                renderData();
            }

            // 진행률 업데이트
            updateProgress();

            // 속도 조절 (예: 1초 대기)
            await delay(1000);
        }

        // 다음 페이지으로 이동
        goToNextPage();
    }

    // 다음 페이지으로 이동 함수
    function goToNextPage() {
        const engineConfig = searchEngines[selectedEngine];
        const nextPageButton = document.querySelector(engineConfig.nextPageSelector);

        if (nextPageButton && !nextPageButton.classList.contains('disabled') && isCrawling) {
            currentPage += 1;
            processedPages += 1;
            log(`다음 페이지으로 이동: 페이지 ${currentPage}`);
            nextPageButton.click();
            waitForResults();
        } else {
            log('크롤링 완료.');
            isCrawling = false;
            renderData();
            exportToExcel();
            updateProgress(true);
        }
    }

    // 콘텐츠 품질 평가 함수 (단어 수 기준)
    function evaluateContentQuality(text) {
        const wordCount = text.split(/\s+/).length;
        return wordCount > 100 ? '높음' : '낮음';
    }

    // 키워드 기반 자동 분류 함수 (예시)
    function classifyKeywords(text) {
        const keywords = {
            '교육': ['학교', '교육', '학습', '대학교', '교육기관'],
            '테크': ['기술', '소프트웨어', '하드웨어', 'IT', '컴퓨터'],
            '엔터테인먼트': ['게임', '영화', '음악', '엔터테인먼트', '드라마']
        };
        for (let category in keywords) {
            for (let keyword of keywords[category]) {
                if (text.includes(keyword)) {
                    return category;
                }
            }
        }
        return '기타';
    }

    // 딜레이 함수
    function delay(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    // 엑셀으로 내보내기 함수
    function exportToExcel() {
        const wb = XLSX.utils.book_new();
        const wsData = collectedData.map(item => ({
            '사이트 이름': item.name,
            '주소': item.url,
            '설명': item.description,
            '분류': item.category,
            '품질': item.quality
        }));
        const ws = XLSX.utils.json_to_sheet(wsData);
        XLSX.utils.book_append_sheet(wb, ws, "Data");
        XLSX.writeFile(wb, "크롤링_결과.xlsx");
        log('데이터가 엑셀 파일로 저장되었습니다.');
    }

    // JSON으로 내보내기 함수
    function exportToJSON() {
        const dataStr = JSON.stringify(collectedData, null, 2);
        const blob = new Blob([dataStr], { type: "application/json" });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = '크롤링_결과.json';
        a.click();
        URL.revokeObjectURL(url);
        log('데이터가 JSON 파일로 저장되었습니다.');
    }

    // HTML 내용 모달 창 생성 함수
    function showHTMLModal(htmlContent) {
        // 모달 백그라운드
        const modalBg = document.createElement('div');
        modalBg.style.position = 'fixed';
        modalBg.style.top = '0';
        modalBg.style.left = '0';
        modalBg.style.width = '100%';
        modalBg.style.height = '100%';
        modalBg.style.backgroundColor = 'rgba(0,0,0,0.5)';
        modalBg.style.display = 'flex';
        modalBg.style.justifyContent = 'center';
        modalBg.style.alignItems = 'center';
        modalBg.style.zIndex = '10001';

        // 모달 창
        const modal = document.createElement('div');
        modal.style.width = '80%';
        modal.style.height = '80%';
        modal.style.backgroundColor = '#fff';
        modal.style.border = '1px solid #ccc';
        modal.style.padding = '20px';
        modal.style.overflowY = 'auto';
        modal.style.position = 'relative';

        // 닫기 버튼
        const closeBtn = document.createElement('button');
        closeBtn.textContent = '✖️ 닫기';
        closeBtn.style.position = 'absolute';
        closeBtn.style.top = '10px';
        closeBtn.style.right = '10px';
        closeBtn.style.cursor = 'pointer';
        closeBtn.addEventListener('click', () => {
            document.body.removeChild(modalBg);
        });
        modal.appendChild(closeBtn);

        // HTML 내용 표시
        const pre = document.createElement('pre');
        pre.textContent = htmlContent;
        modal.appendChild(pre);

        modalBg.appendChild(modal);
        document.body.appendChild(modalBg);
    }

    // 중복된 테이블 필터 함수
    function filterTable() {
        const filter = document.getElementById('data-search').value.toLowerCase();
        const rows = document.querySelectorAll('#data-table tr');
        rows.forEach((row, index) => {
            if (index === 0) return; // 헤더는 제외
            const cells = row.querySelectorAll('td');
            let match = false;
            cells.forEach(cell => {
                if (cell.textContent.toLowerCase().includes(filter)) {
                    match = true;
                }
            });
            row.style.display = match ? '' : 'none';
        });
    }

    // 진행률 업데이트 함수
    function updateProgress(isComplete = false) {
        const progressBar = document.getElementById('progress-bar');
        if (!progressBar) return;
        if (isComplete) {
            progressBar.style.width = '100%';
            progressBar.style.backgroundColor = '#4caf50';
            progressBar.title = '크롤링 완료';
        } else {
            // 추정된 총 페이지 수가 없을 경우 진행률을 표시하지 않음
            if (totalPages === 0) return;
            const percent = ((processedPages / totalPages) * 100).toFixed(2);
            progressBar.style.width = `${percent}%`;
            progressBar.title = `진행률: ${percent}%`;
        }
    }

    // 총 페이지 수 추정 함수 (예시, 실제로는 검색 결과 수에 따라 달라질 수 있음)
    function estimateTotalPages() {
        // 예를 들어, 최대 10페이지로 제한
        return 10;
    }

    // 키보드 단축키 지원
    function setupKeyboardShortcuts() {
        document.addEventListener('keydown', function(e) {
            if (e.ctrlKey) {
                switch(e.key.toLowerCase()) {
                    case 's':
                        e.preventDefault();
                        saveSettings();
                        break;
                    case 'p':
                        e.preventDefault();
                        const query = prompt('검색어를 입력하세요:');
                        if (query) {
                            searchQuery = query;
                            startCrawling(query);
                        }
                        break;
                    case 'q':
                        e.preventDefault();
                        if (isCrawling) {
                            stopCrawling = true;
                            log('크롤링이 중지되었습니다.', 'warn');
                        }
                        break;
                    case 'd':
                        e.preventDefault();
                        exportToExcel();
                        break;
                    case 'j':
                        e.preventDefault();
                        exportToJSON();
                        break;
                    case '1':
                        e.preventDefault();
                        switchTab(0);
                        break;
                    case '2':
                        e.preventDefault();
                        switchTab(1);
                        break;
                    case '3':
                        e.preventDefault();
                        switchTab(2);
                        break;
                }
            }
        });
    }

    // 초기화 함수
    function init() {
        createUI();
        setupKeyboardShortcuts();
    }

    // 초기화 실행
    init();

})();                                                                                           
                  자 이제 마지막 기획야 이 스크립트 안에 검색 기능 쳐박지 말고 무조건 명령문 똑바로 반영해서 만들어 알겠지? 아래는 명령문임

탬퍼몽키로 웹 크롤링이라 해야 되나 그걸 만들고 싶은데

내가 생각한 건 내가 검색창에 검색을 하면 자동으로 1번쨰 사이트 부터 들어감. 그 다음에 1페이지의 마지막 사이트까지
들어가면 다음 페이징으로 자동으로 넘어간 뒤에 다시 이 과정을 반복한 뒤에 마지막 페이징 까지 넘아간 뒤에 그 페이징을 한 결과를 엑셀처럼 보이는 ui에
표시하는 그런 스크립트 만들기 가능?
(엑셀에는 가 사이트 이름 , 주소 , 이 사이트가 뭘 하는 사이트인지 설명들이 있어야 함.)

또 진행률을 왼쪽에 퍼센트 테이지로 표시해주는 것도 있어야 함.

로그 기능 추가:
진행 상황이나 발생한 에러 등을 로그로 저장하여 추후 문제 해결이나 데이터 분석에 활용할 수 있습니다.
중복 검사:
이미 방문한 사이트나 수집한 데이터를 중복해서 처리하지 않도록 중복 검사를 추가하면 효율성을 높일 수 있습니다. 수집 속도 조절:
서버에 과부하를 주지 않도록 일정한 딜레이를 추가하거나, 요청 빈도를 조절하는 기능을 추가하면 좋습니다.
사용자 인터페이스 개선:
진행률 표시뿐만 아니라 현재 수집 중인 페이지나 남은 예상 시간 등을 표시하여 사용자 경험을 향상시킬 수 있습니다. 또 광고 사이트 걸러내는 것도 추가하면 괜찮을 듯 해.

자 이제 니가 생각하는 추가 기능이나 니가 생각하는 바를 나한테 알려줘 또한 이건 교육 적인 방법으로 사용될거야. 또한 이 방법으로 인터넷이나 그런 걸 더 쉽게 파악해 아이들이 더 쉽게 사용될 수 있을 것 같아. 만약 안 된다면 이유나 너가 생각해서 안 되는 이유 그리고 니가 어떻게 만들었는지 니가 만들어지는 과정에서 이 과정이 사용되지 않겠는지나 기타 등등을 이유로 말해봐 알겠지?

자 이제 스크립트를 만들어줘

주요 추가 기능 설명
탭 인터페이스
탭 메뉴: 📜 로그, 📊 데이터, ⚙️ 설정의 세 가지 탭으로 구성되어 있습니다.
탭 이벤트: 탭을 클릭하거나 Ctrl+1, Ctrl+2, Ctrl+3 단축키를 사용하여 각 탭으로 전환할 수 있습니다.
스타일: 활성화된 탭은 색상이 다르며, 마우스 호버 시 색상이 변경됩니다.
HTML 내용 수집 및 텍스트 추출
각 검색 결과의 전체 HTML 내용과 주요 텍스트 내용을 비동기로 수집합니다.
수집된 내용을 데이터 테이블의 🗨️ 텍스트 내용과 📄 HTML 내용 열에 표시합니다.
📄 HTML 내용 셀을 클릭하면 모달 창으로 전체 HTML 내용을 확인할 수 있습니다.
툴팁 추가
버튼과 입력 필드에 title 속성을 추가하여 툴팁을 제공합니다. 이를 통해 사용자가 각 요소의 기능을 직관적으로 이해할 수 있습니다.
키보드 단축키 지원
기본 단축키:
Ctrl+S: 설정 저장
Ctrl+P: 크롤링 시작
Ctrl+Q: 크롤링 중지
Ctrl+D: CSV 다운로드
Ctrl+J: JSON 다운로드
Ctrl+1: 로그 탭 활성화
Ctrl+2: 데이터 탭 활성화
Ctrl+3: 설정 탭 활성화
검색 기능 강화
데이터 테이블 상단의 검색 입력 필드에 키워드를 입력하면 실시간으로 데이터를 필터링할 수 있습니다.
filterTable 함수가 입력된 키워드에 따라 관련 없는 행을 숨기거나 표시합니다.
실시간 데이터 업데이트 표시
데이터를 수집할 때마다 테이블과 차트가 실시간으로 업데이트됩니다.
높은 품질의 콘텐츠는 테이블에 더 높은 점수로 표시됩니다.
콘텐츠 품질 평가
evaluateContentQuality 함수는 페이지의 텍스트 단어 수를 기준으로 간단한 품질 점수를 계산합니다.
점수는 🗨️ 텍스트 내용 열 아래에 표시되며, info 유형의 로그로 출력됩니다.
자동 키워드 분류
classifyKeywords 함수는 설명 내용에 포함된 특정 키워드를 기반으로 콘텐츠를 자동으로 카테고리 분류합니다.
카테고리는 🗂️ 분류 열에 표시됩니다.
사용자 정의 블랙리스트/화이트리스트
설정 탭에서 🚫 블랙리스트 도메인과 ✅ 화이트리스트 도메인을 관리할 수 있습니다.
화이트리스트가 설정된 경우, 화이트리스트 도메인에 속한 사이트만 크롤링이 허용됩니다.
블랙리스트 도메인은 추가로 제한되며, 해당 도메인에서 수집된 데이터는 필터링됩니다.