// ==UserScript== // @name 智能内容提取器 // @namespace http://tampermonkey.net/ // @version 1.0 // @description 智能提取网页内容,支持表格、列表、文章等多种格式导出 // @author Trae AI Assistant // @match *://*/* // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // @grant GM_download // @license MIT // @downloadURL https://update.greasyfork.icu/scripts/543396/%E6%99%BA%E8%83%BD%E5%86%85%E5%AE%B9%E6%8F%90%E5%8F%96%E5%99%A8.user.js // @updateURL https://update.greasyfork.icu/scripts/543396/%E6%99%BA%E8%83%BD%E5%86%85%E5%AE%B9%E6%8F%90%E5%8F%96%E5%99%A8.meta.js // ==/UserScript== (function() { 'use strict'; // 内容提取器类 class ContentExtractor { constructor() { this.extractedData = []; this.currentMode = 'auto'; this.selectedElements = []; this.isSelecting = false; this.init(); } init() { this.createFloatingButton(); this.createExtractionPanel(); this.bindEvents(); } // 创建悬浮按钮 createFloatingButton() { const button = document.createElement('div'); button.id = 'content-extractor-btn'; button.innerHTML = '📊'; button.title = '内容提取器'; GM_addStyle(` #content-extractor-btn { position: fixed; bottom: 100px; right: 20px; width: 56px; height: 56px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 24px; cursor: pointer; z-index: 9999; box-shadow: 0 4px 20px rgba(0,0,0,0.2); transition: all 0.3s ease; } #content-extractor-btn:hover { transform: scale(1.1); box-shadow: 0 6px 25px rgba(0,0,0,0.3); } #content-extractor-btn.active { background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%); } `); document.body.appendChild(button); this.floatingBtn = button; } // 创建提取面板 createExtractionPanel() { const panel = document.createElement('div'); panel.id = 'extraction-panel'; panel.innerHTML = `

📊 内容提取器

准备就绪
已提取: 0 项

导出选项

`; GM_addStyle(` #extraction-panel { position: fixed; top: 50%; right: 20px; transform: translateY(-50%); width: 350px; max-height: 80vh; background: white; border: 1px solid #e1e8ed; border-radius: 12px; box-shadow: 0 8px 32px rgba(0,0,0,0.15); z-index: 10000; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; display: none; overflow-y: auto; } .panel-header { display: flex; justify-content: space-between; align-items: center; padding: 16px 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 12px 12px 0 0; } .panel-header h3 { margin: 0; font-size: 16px; font-weight: 600; } #panel-close { background: none; border: none; color: white; font-size: 20px; cursor: pointer; padding: 0; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; border-radius: 4px; } #panel-close:hover { background: rgba(255,255,255,0.2); } .panel-content { padding: 20px; } .mode-selector { margin-bottom: 16px; } .mode-selector label { display: block; margin-bottom: 6px; font-weight: 500; color: #2d3748; } .mode-selector select { width: 100%; padding: 8px 12px; border: 1px solid #cbd5e0; border-radius: 6px; background: white; font-size: 14px; outline: none; } .extraction-options { margin-bottom: 20px; padding: 12px; background: #f7fafc; border-radius: 6px; } .extraction-options label { display: block; margin-bottom: 8px; font-size: 14px; color: #4a5568; cursor: pointer; } .extraction-options input[type="checkbox"] { margin-right: 8px; } .action-buttons { display: flex; gap: 8px; margin-bottom: 16px; flex-wrap: wrap; } .action-buttons button { flex: 1; padding: 10px 12px; border: none; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500; transition: all 0.2s; } .primary-btn { background: #4299e1; color: white; } .primary-btn:hover { background: #3182ce; } .secondary-btn { background: #718096; color: white; } .secondary-btn:hover { background: #2d3748; } .warning-btn { background: #f56565; color: white; } .warning-btn:hover { background: #e53e3e; } .extraction-status { padding: 12px; background: #edf2f7; border-radius: 6px; font-size: 13px; } #status-text { color: #4a5568; margin-bottom: 4px; } #data-count { color: #2b6cb0; font-weight: 500; } .export-section { border-top: 1px solid #e2e8f0; padding: 16px 20px; } .export-section h4 { margin: 0 0 12px 0; font-size: 14px; color: #2d3748; } .export-buttons { display: flex; gap: 6px; flex-wrap: wrap; } .export-buttons button { flex: 1; padding: 6px 10px; border: 1px solid #cbd5e0; background: white; border-radius: 4px; cursor: pointer; font-size: 12px; color: #4a5568; transition: all 0.2s; } .export-buttons button:hover { background: #f7fafc; border-color: #a0aec0; } .preview-section { border-top: 1px solid #e2e8f0; padding: 16px 20px; max-height: 300px; overflow-y: auto; } .preview-section h4 { margin: 0 0 12px 0; font-size: 14px; color: #2d3748; } .preview-container { background: #f7fafc; border: 1px solid #e2e8f0; border-radius: 4px; padding: 12px; font-size: 12px; font-family: 'Monaco', 'Menlo', monospace; white-space: pre-wrap; word-break: break-all; } .highlight-element { outline: 2px solid #4299e1 !important; background: rgba(66, 153, 225, 0.1) !important; cursor: pointer !important; } .selected-element { outline: 2px solid #48bb78 !important; background: rgba(72, 187, 120, 0.2) !important; } `); document.body.appendChild(panel); this.panel = panel; } // 绑定事件 bindEvents() { // 悬浮按钮点击事件 this.floatingBtn.addEventListener('click', () => { this.togglePanel(); }); // 面板关闭按钮 document.getElementById('panel-close').addEventListener('click', () => { this.hidePanel(); }); // 开始提取按钮 document.getElementById('start-extraction').addEventListener('click', () => { this.startExtraction(); }); // 预览数据按钮 document.getElementById('preview-data').addEventListener('click', () => { this.previewData(); }); // 清除选择按钮 document.getElementById('clear-selection').addEventListener('click', () => { this.clearSelection(); }); // 导出按钮事件 document.getElementById('export-json').addEventListener('click', () => this.exportData('json')); document.getElementById('export-csv').addEventListener('click', () => this.exportData('csv')); document.getElementById('export-excel').addEventListener('click', () => this.exportData('excel')); document.getElementById('export-txt').addEventListener('click', () => this.exportData('txt')); document.getElementById('export-markdown').addEventListener('click', () => this.exportData('markdown')); } // 切换面板显示 togglePanel() { if (this.panel.style.display === 'none' || !this.panel.style.display) { this.showPanel(); } else { this.hidePanel(); } } // 显示面板 showPanel() { this.panel.style.display = 'block'; this.floatingBtn.classList.add('active'); } // 隐藏面板 hidePanel() { this.panel.style.display = 'none'; this.floatingBtn.classList.remove('active'); this.stopCustomSelection(); } // 智能识别页面内容类型 detectContentType() { const tables = document.querySelectorAll('table'); const lists = document.querySelectorAll('ul, ol'); const articles = document.querySelectorAll('article, .article, .content, .post'); if (tables.length > 0) return 'table'; if (lists.length > 0) return 'list'; if (articles.length > 0) return 'article'; return 'custom'; } // 提取表格数据 extractTableData() { const tables = document.querySelectorAll('table'); const data = []; tables.forEach((table, tableIndex) => { const tableData = { tableIndex: tableIndex + 1, headers: [], rows: [] }; // 提取表头 const headers = table.querySelectorAll('thead th, tr:first-child th, tr:first-child td'); if (headers.length > 0) { tableData.headers = Array.from(headers).map(th => this.cleanText(th.textContent)); } // 提取数据行 const rows = table.querySelectorAll('tbody tr, tr'); rows.forEach((row, rowIndex) => { if (rowIndex === 0 && headers.length > 0) return; // 跳过表头行 const cells = row.querySelectorAll('td, th'); if (cells.length > 0) { const rowData = Array.from(cells).map(cell => ({ text: this.cleanText(cell.textContent), html: cell.innerHTML, links: this.extractLinks(cell) })); tableData.rows.push(rowData); } }); if (tableData.rows.length > 0) { data.push(tableData); } }); return data; } // 提取列表数据 extractListData() { const lists = document.querySelectorAll('ul, ol'); const data = []; lists.forEach((list, listIndex) => { const listData = { listIndex: listIndex + 1, type: list.tagName.toLowerCase(), items: [] }; const items = list.querySelectorAll('li'); items.forEach(item => { listData.items.push({ text: this.cleanText(item.textContent), html: item.innerHTML, links: this.extractLinks(item) }); }); if (listData.items.length > 0) { data.push(listData); } }); return data; } // 提取文章内容 extractArticleData() { const selectors = [ 'article', '.article', '.content', '.post', '.entry-content', '.post-content', 'main', '[role="main"]' ]; let article = null; for (const selector of selectors) { article = document.querySelector(selector); if (article) break; } if (!article) { // 尝试智能识别主要内容区域 const contentElements = document.querySelectorAll('div, section'); let maxTextLength = 0; contentElements.forEach(el => { const textLength = el.textContent.length; if (textLength > maxTextLength) { maxTextLength = textLength; article = el; } }); } if (!article) return []; const data = { title: this.extractTitle(), content: this.cleanText(article.textContent), paragraphs: [], headings: [], links: this.extractLinks(article), images: this.extractImages(article) }; // 提取段落 const paragraphs = article.querySelectorAll('p'); data.paragraphs = Array.from(paragraphs).map(p => this.cleanText(p.textContent)).filter(text => text.length > 0); // 提取标题 const headings = article.querySelectorAll('h1, h2, h3, h4, h5, h6'); data.headings = Array.from(headings).map(h => ({ level: parseInt(h.tagName.charAt(1)), text: this.cleanText(h.textContent) })); return [data]; } // 提取所有图片 extractAllImages() { const images = document.querySelectorAll('img[src]'); return Array.from(images).map((img, index) => ({ index: index + 1, src: img.src, alt: img.alt || '', title: img.title || '', width: img.naturalWidth || img.width, height: img.naturalHeight || img.height })); } // 提取所有链接 extractAllLinks() { const links = document.querySelectorAll('a[href]'); return Array.from(links).map((link, index) => ({ index: index + 1, text: this.cleanText(link.textContent), url: link.href, title: link.title || '', target: link.target || '' })); } // 开始自定义选择 startCustomSelection() { this.isSelecting = true; this.selectedElements = []; document.getElementById('status-text').textContent = '请点击要提取的元素...'; // 添加鼠标事件监听 document.addEventListener('mouseover', this.handleMouseOver.bind(this)); document.addEventListener('mouseout', this.handleMouseOut.bind(this)); document.addEventListener('click', this.handleElementClick.bind(this)); } // 停止自定义选择 stopCustomSelection() { this.isSelecting = false; document.removeEventListener('mouseover', this.handleMouseOver.bind(this)); document.removeEventListener('mouseout', this.handleMouseOut.bind(this)); document.removeEventListener('click', this.handleElementClick.bind(this)); // 清除高亮 document.querySelectorAll('.highlight-element').forEach(el => { el.classList.remove('highlight-element'); }); } // 鼠标悬停事件 handleMouseOver(e) { if (!this.isSelecting) return; if (this.panel.contains(e.target) || this.floatingBtn.contains(e.target)) return; e.target.classList.add('highlight-element'); } // 鼠标离开事件 handleMouseOut(e) { if (!this.isSelecting) return; if (this.panel.contains(e.target) || this.floatingBtn.contains(e.target)) return; e.target.classList.remove('highlight-element'); } // 元素点击事件 handleElementClick(e) { if (!this.isSelecting) return; if (this.panel.contains(e.target) || this.floatingBtn.contains(e.target)) return; e.preventDefault(); e.stopPropagation(); if (e.target.classList.contains('selected-element')) { e.target.classList.remove('selected-element'); this.selectedElements = this.selectedElements.filter(el => el !== e.target); } else { e.target.classList.add('selected-element'); this.selectedElements.push(e.target); } document.getElementById('data-count').textContent = `已选择: ${this.selectedElements.length} 个元素`; } // 提取页面标题 extractTitle() { return document.title || document.querySelector('h1')?.textContent || document.querySelector('.title')?.textContent || '未知标题'; } // 提取链接 extractLinks(element) { const links = element.querySelectorAll('a[href]'); return Array.from(links).map(link => ({ text: this.cleanText(link.textContent), url: link.href, title: link.title })); } // 提取图片 extractImages(element) { const images = element.querySelectorAll('img[src]'); return Array.from(images).map(img => ({ src: img.src, alt: img.alt, title: img.title, width: img.width, height: img.height })); } // 清理文本 cleanText(text) { if (!text) return ''; return text.replace(/\s+/g, ' ').trim(); } // 根据类型提取 extractByType(type) { switch (type) { case 'table': return this.extractTableData(); case 'list': return this.extractListData(); case 'article': return this.extractArticleData(); case 'image': return this.extractAllImages(); case 'link': return this.extractAllLinks(); default: return []; } } // 提取自定义选择的元素 extractCustomData() { return this.selectedElements.map((element, index) => ({ index: index + 1, tagName: element.tagName.toLowerCase(), text: this.cleanText(element.textContent), html: element.innerHTML, links: this.extractLinks(element), images: this.extractImages(element) })); } // 开始提取 startExtraction() { const mode = document.getElementById('extraction-mode').value; const statusText = document.getElementById('status-text'); const dataCount = document.getElementById('data-count'); statusText.textContent = '正在提取...'; let extractedData = []; try { switch (mode) { case 'auto': const detectedType = this.detectContentType(); extractedData = this.extractByType(detectedType); break; case 'table': extractedData = this.extractTableData(); break; case 'list': extractedData = this.extractListData(); break; case 'article': extractedData = this.extractArticleData(); break; case 'image': extractedData = this.extractAllImages(); break; case 'link': extractedData = this.extractAllLinks(); break; case 'custom': if (this.selectedElements.length === 0) { this.startCustomSelection(); return; } else { extractedData = this.extractCustomData(); this.stopCustomSelection(); } break; } this.extractedData = extractedData; statusText.textContent = '提取完成'; dataCount.textContent = `已提取: ${this.getDataItemCount()} 项`; } catch (error) { statusText.textContent = '提取失败: ' + error.message; console.error('Content extraction error:', error); } } // 获取数据项数量 getDataItemCount() { if (!this.extractedData || this.extractedData.length === 0) return 0; let count = 0; this.extractedData.forEach(item => { if (item.rows) { count += item.rows.length; } else if (item.items) { count += item.items.length; } else if (item.paragraphs) { count += item.paragraphs.length; } else { count += 1; } }); return count; } // 预览数据 previewData() { const previewSection = document.getElementById('preview-section'); const previewContainer = document.getElementById('preview-container'); if (!this.extractedData || this.extractedData.length === 0) { previewContainer.textContent = '暂无数据,请先提取内容'; } else { previewContainer.textContent = JSON.stringify(this.extractedData, null, 2); } previewSection.style.display = 'block'; } // 清除选择 clearSelection() { this.selectedElements.forEach(el => { el.classList.remove('selected-element'); }); this.selectedElements = []; this.extractedData = []; this.stopCustomSelection(); document.getElementById('status-text').textContent = '准备就绪'; document.getElementById('data-count').textContent = '已提取: 0 项'; document.getElementById('preview-section').style.display = 'none'; } // 导出数据 exportData(format) { if (!this.extractedData || this.extractedData.length === 0) { alert('暂无数据可导出,请先提取内容'); return; } let content = ''; let filename = `extracted_data_${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}`; switch (format) { case 'json': content = JSON.stringify(this.extractedData, null, 2); filename += '.json'; break; case 'csv': content = this.convertToCSV(this.extractedData); filename += '.csv'; break; case 'excel': content = this.convertToExcel(this.extractedData); filename += '.xlsx'; break; case 'txt': content = this.convertToText(this.extractedData); filename += '.txt'; break; case 'markdown': content = this.convertToMarkdown(this.extractedData); filename += '.md'; break; } this.downloadFile(content, filename); } // 转换为CSV格式 convertToCSV(data) { const rows = []; data.forEach(item => { if (item.rows && item.headers) { // 表格数据 if (item.headers.length > 0) { rows.push(item.headers.join(',')); } item.rows.forEach(row => { const csvRow = row.map(cell => `"${cell.text.replace(/"/g, '""')}"`); rows.push(csvRow.join(',')); }); } else if (item.items) { // 列表数据 rows.push('项目'); item.items.forEach(listItem => { rows.push(`"${listItem.text.replace(/"/g, '""')}"`); }); } else if (item.paragraphs) { // 文章数据 rows.push('段落'); item.paragraphs.forEach(paragraph => { rows.push(`"${paragraph.replace(/"/g, '""')}"`); }); } else { // 其他数据 const keys = Object.keys(item); if (rows.length === 0) { rows.push(keys.join(',')); } const values = keys.map(key => `"${String(item[key]).replace(/"/g, '""')}"`); rows.push(values.join(',')); } }); return rows.join('\n'); } // 转换为Excel格式(简化版,实际生成CSV格式) convertToExcel(data) { // 由于浏览器环境限制,这里生成CSV格式,用户可以用Excel打开 return this.convertToCSV(data); } // 转换为文本格式 convertToText(data) { const lines = []; lines.push('网页内容提取结果'); lines.push('='.repeat(50)); lines.push(`提取时间: ${new Date().toLocaleString()}`); lines.push(`页面标题: ${document.title}`); lines.push(`页面URL: ${window.location.href}`); lines.push(''); data.forEach((item, index) => { lines.push(`【数据块 ${index + 1}】`); if (item.rows && item.headers) { // 表格数据 lines.push(`类型: 表格数据`); if (item.headers.length > 0) { lines.push(`表头: ${item.headers.join(' | ')}`); } lines.push(`数据行数: ${item.rows.length}`); lines.push(''); item.rows.forEach((row, rowIndex) => { const rowText = row.map(cell => cell.text).join(' | '); lines.push(`${rowIndex + 1}. ${rowText}`); }); } else if (item.items) { // 列表数据 lines.push(`类型: ${item.type.toUpperCase()}列表`); lines.push(`项目数: ${item.items.length}`); lines.push(''); item.items.forEach((listItem, itemIndex) => { lines.push(`${itemIndex + 1}. ${listItem.text}`); }); } else if (item.title && item.paragraphs) { // 文章数据 lines.push(`类型: 文章内容`); lines.push(`标题: ${item.title}`); lines.push(`段落数: ${item.paragraphs.length}`); lines.push(`链接数: ${item.links.length}`); lines.push(`图片数: ${item.images.length}`); lines.push(''); if (item.headings.length > 0) { lines.push('文章结构:'); item.headings.forEach(heading => { const indent = ' '.repeat(heading.level - 1); lines.push(`${indent}- ${heading.text}`); }); lines.push(''); } lines.push('内容:'); item.paragraphs.forEach((paragraph, pIndex) => { lines.push(`${pIndex + 1}. ${paragraph}`); lines.push(''); }); } else if (item.src) { // 图片数据 lines.push(`类型: 图片`); lines.push(`链接: ${item.src}`); lines.push(`描述: ${item.alt || '无'}`); lines.push(`尺寸: ${item.width}x${item.height}`); } else if (item.url) { // 链接数据 lines.push(`类型: 超链接`); lines.push(`文本: ${item.text}`); lines.push(`链接: ${item.url}`); lines.push(`标题: ${item.title || '无'}`); } else { // 自定义数据 lines.push(`类型: 自定义元素`); lines.push(`标签: ${item.tagName}`); lines.push(`内容: ${item.text}`); } lines.push(''); lines.push('-'.repeat(30)); lines.push(''); }); return lines.join('\n'); } // 转换为Markdown格式 convertToMarkdown(data) { const lines = []; lines.push('# 网页内容提取结果\n'); lines.push(`**提取时间:** ${new Date().toLocaleString()}`); lines.push(`**页面标题:** ${document.title}`); lines.push(`**页面URL:** ${window.location.href}\n`); data.forEach((item, index) => { lines.push(`## 数据块 ${index + 1}\n`); if (item.rows && item.headers) { // 表格数据 lines.push('**类型:** 表格数据\n'); if (item.headers.length > 0) { // Markdown表格格式 lines.push(`| ${item.headers.join(' | ')} |`); lines.push(`| ${item.headers.map(() => '---').join(' | ')} |`); item.rows.forEach(row => { const rowText = row.map(cell => cell.text.replace(/\|/g, '\\|')).join(' | '); lines.push(`| ${rowText} |`); }); lines.push(''); } } else if (item.items) { // 列表数据 lines.push(`**类型:** ${item.type.toUpperCase()}列表\n`); item.items.forEach((listItem, itemIndex) => { if (item.type === 'ol') { lines.push(`${itemIndex + 1}. ${listItem.text}`); } else { lines.push(`- ${listItem.text}`); } }); lines.push(''); } else if (item.title && item.paragraphs) { // 文章数据 lines.push('**类型:** 文章内容\n'); lines.push(`**标题:** ${item.title}\n`); if (item.headings.length > 0) { lines.push('### 文章结构\n'); item.headings.forEach(heading => { const prefix = '#'.repeat(heading.level + 2); lines.push(`${prefix} ${heading.text}`); }); lines.push(''); } lines.push('### 内容\n'); item.paragraphs.forEach(paragraph => { lines.push(paragraph + '\n'); }); if (item.links.length > 0) { lines.push('### 相关链接\n'); item.links.forEach(link => { lines.push(`- [${link.text}](${link.url})`); }); lines.push(''); } } else if (item.src) { // 图片数据 lines.push('**类型:** 图片\n'); lines.push(`![${item.alt}](${item.src})`); lines.push(`- **描述:** ${item.alt || '无'}`); lines.push(`- **尺寸:** ${item.width}x${item.height}\n`); } else if (item.url) { // 链接数据 lines.push('**类型:** 超链接\n'); lines.push(`[${item.text}](${item.url})`); if (item.title) lines.push(`- **标题:** ${item.title}`); lines.push(''); } else { // 自定义数据 lines.push('**类型:** 自定义元素\n'); lines.push(`- **标签:** \`${item.tagName}\``); lines.push(`- **内容:** ${item.text}\n`); } lines.push('---\n'); }); return lines.join('\n'); } // 下载文件 downloadFile(content, filename) { try { // 使用GM_download如果可用 if (typeof GM_download !== 'undefined') { const blob = new Blob([content], { type: 'text/plain;charset=utf-8' }); const url = URL.createObjectURL(blob); GM_download(url, filename); URL.revokeObjectURL(url); } else { // 降级到标准下载方法 const blob = new Blob([content], { type: 'text/plain;charset=utf-8' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } document.getElementById('status-text').textContent = '导出成功!'; setTimeout(() => { document.getElementById('status-text').textContent = '准备就绪'; }, 2000); } catch (error) { console.error('Download error:', error); document.getElementById('status-text').textContent = '导出失败:' + error.message; } } // 保存设置到本地存储 saveSettings() { const settings = { mode: document.getElementById('extraction-mode').value, includeHeaders: document.getElementById('include-headers').checked, cleanData: document.getElementById('clean-data').checked, preserveLinks: document.getElementById('preserve-links').checked }; if (typeof GM_setValue !== 'undefined') { GM_setValue('extractor_settings', JSON.stringify(settings)); } else { localStorage.setItem('extractor_settings', JSON.stringify(settings)); } } // 从本地存储加载设置 loadSettings() { let settings = null; try { if (typeof GM_getValue !== 'undefined') { const saved = GM_getValue('extractor_settings', null); if (saved) settings = JSON.parse(saved); } else { const saved = localStorage.getItem('extractor_settings'); if (saved) settings = JSON.parse(saved); } if (settings) { document.getElementById('extraction-mode').value = settings.mode || 'auto'; document.getElementById('include-headers').checked = settings.includeHeaders !== false; document.getElementById('clean-data').checked = settings.cleanData !== false; document.getElementById('preserve-links').checked = settings.preserveLinks || false; } } catch (error) { console.warn('Failed to load settings:', error); } } // 初始化完成后加载设置 initComplete() { this.loadSettings(); // 监听设置变化并自动保存 const settingsElements = [ 'extraction-mode', 'include-headers', 'clean-data', 'preserve-links' ]; settingsElements.forEach(id => { const element = document.getElementById(id); if (element) { element.addEventListener('change', () => { this.saveSettings(); }); } }); } } // 等待页面加载完成后初始化 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { const extractor = new ContentExtractor(); setTimeout(() => extractor.initComplete(), 100); }); } else { const extractor = new ContentExtractor(); setTimeout(() => extractor.initComplete(), 100); } })();