// ==UserScript== // @name Universal Page Inspector // @namespace http://tampermonkey.net/ // @version 1.3 // @description 通用页面检查器,获取页面各种信息 // @author You // @match *://*/* // @grant GM_xmlhttpRequest // @grant GM_getValue // @grant GM_setValue // @grant GM_addStyle // ==/UserScript== (function() { 'use strict'; // 创建检查按钮 const inspectBtn = document.createElement('button'); inspectBtn.textContent = '🔍 检查页面'; inspectBtn.id = 'page-inspector-btn'; inspectBtn.style.position = 'fixed'; inspectBtn.style.top = '8%'; inspectBtn.style.right = '1%'; inspectBtn.style.padding = '8px 16px'; inspectBtn.style.backgroundColor = '#007bff'; inspectBtn.style.color = 'white'; inspectBtn.style.border = 'none'; inspectBtn.style.borderRadius = '8px'; inspectBtn.style.cursor = 'pointer'; inspectBtn.style.zIndex = '99999'; inspectBtn.style.fontSize = '12px'; inspectBtn.style.fontWeight = 'bold'; // 创建结果弹窗 const createInspectPopup = (content) => { // 移除旧的弹窗 const oldPopup = document.getElementById('inspector-popup'); if (oldPopup) oldPopup.remove(); // 创建新弹窗 const popup = document.createElement('div'); popup.id = 'inspector-popup'; popup.style.position = 'fixed'; popup.style.top = '50%'; popup.style.left = '50%'; popup.style.transform = 'translate(-50%, -50%)'; popup.style.width = '85%'; popup.style.height = '85%'; popup.style.backgroundColor = '#ffffff'; popup.style.border = '2px solid #444'; popup.style.borderRadius = '12px'; popup.style.boxShadow = '0 0 60px rgba(0,0,0,0.3)'; popup.style.zIndex = '100000'; popup.style.overflow = 'hidden'; popup.style.display = 'flex'; popup.style.flexDirection = 'column'; // 标题栏 const titleBar = document.createElement('div'); titleBar.style.padding = '12px 20px'; titleBar.style.backgroundColor = '#2c3e50'; titleBar.style.color = 'white'; titleBar.style.fontWeight = 'bold'; titleBar.style.display = 'flex'; titleBar.style.justifyContent = 'space-between'; titleBar.style.alignItems = 'center'; const title = document.createElement('span'); title.textContent = '页面检查器'; titleBar.appendChild(title); const closeBtn = document.createElement('button'); closeBtn.textContent = '✕'; closeBtn.style.background = 'none'; closeBtn.style.border = 'none'; closeBtn.style.color = 'white'; closeBtn.style.cursor = 'pointer'; closeBtn.style.fontSize = '18px'; closeBtn.style.padding = '0 8px'; closeBtn.addEventListener('click', () => popup.remove()); titleBar.appendChild(closeBtn); // 选项卡容器 const tabContainer = document.createElement('div'); tabContainer.style.display = 'flex'; tabContainer.style.backgroundColor = '#34495e'; tabContainer.style.padding = '0'; tabContainer.style.gap = '1px'; tabContainer.style.overflowX = 'auto'; // 内容容器 const contentContainer = document.createElement('div'); contentContainer.style.flex = '1'; contentContainer.style.display = 'flex'; contentContainer.style.flexDirection = 'column'; contentContainer.style.overflow = 'hidden'; // 创建选项卡 const createTab = (id, label, content) => { const tab = document.createElement('button'); tab.textContent = label; tab.dataset.tab = id; tab.style.padding = '10px 16px'; tab.style.backgroundColor = '#34495e'; tab.style.color = '#ecf0f1'; tab.style.border = 'none'; tab.style.cursor = 'pointer'; tab.style.whiteSpace = 'nowrap'; tab.style.fontSize = '13px'; tab.style.fontWeight = 'bold'; tab.style.transition = 'background-color 0.2s'; tab.addEventListener('click', () => { // 移除所有激活状态 tabContainer.querySelectorAll('button').forEach(t => { t.style.backgroundColor = '#34495e'; }); // 激活当前选项卡 tab.style.backgroundColor = '#2c3e50'; // 显示对应内容 contentContainer.querySelectorAll('.tab-content').forEach(c => { c.style.display = 'none'; }); contentContainer.querySelector(`#tab-${id}`).style.display = 'block'; }); // 创建内容区域 const tabContent = document.createElement('div'); tabContent.id = `tab-${id}`; tabContent.className = 'tab-content'; tabContent.style.display = 'none'; tabContent.style.flex = '1'; tabContent.style.padding = '20px'; tabContent.style.overflow = 'auto'; tabContent.style.fontFamily = 'Consolas, Monaco, monospace'; tabContent.style.fontSize = '13px'; tabContent.style.lineHeight = '1.6'; tabContent.style.whiteSpace = 'pre-wrap'; tabContent.style.color = '#2c3e50'; tabContent.textContent = content; contentContainer.appendChild(tabContent); return tab; }; // 添加选项卡 const tabs = [ createTab('overview', '概览', content.overview), createTab('elements', '元素检查', content.elements), createTab('images', '图片分析', content.images), createTab('links', '链接分析', content.links), createTab('storage', '存储信息', content.storage), createTab('network', '网络信息', content.network), createTab('performance', '性能信息', content.performance), createTab('console', '控制台', content.console) ]; // 设置第一个选项卡为激活状态 if (tabs[0]) { tabs[0].style.backgroundColor = '#2c3e50'; contentContainer.querySelector('#tab-overview').style.display = 'block'; } // 添加选项卡到容器 tabs.forEach(tab => tabContainer.appendChild(tab)); // 复制按钮 const copyBtn = document.createElement('button'); copyBtn.textContent = '📋 复制当前'; copyBtn.style.position = 'absolute'; copyBtn.style.top = '15px'; copyBtn.style.right = '60px'; copyBtn.style.padding = '6px 12px'; copyBtn.style.backgroundColor = '#27ae60'; copyBtn.style.color = 'white'; copyBtn.style.border = 'none'; copyBtn.style.borderRadius = '5px'; copyBtn.style.cursor = 'pointer'; copyBtn.style.fontSize = '12px'; copyBtn.style.fontWeight = 'bold'; copyBtn.addEventListener('click', () => { const activeTab = tabContainer.querySelector('button[style*="background-color: rgb(44, 62, 80)"]'); const tabId = activeTab ? activeTab.dataset.tab : 'overview'; const activeContent = content[tabId]; navigator.clipboard.writeText(activeContent).then(() => { const originalText = copyBtn.textContent; copyBtn.textContent = '✅ 已复制!'; setTimeout(() => { copyBtn.textContent = originalText; }, 2000); }); }); titleBar.appendChild(copyBtn); // 组装弹窗 popup.appendChild(titleBar); popup.appendChild(tabContainer); popup.appendChild(contentContainer); document.body.appendChild(popup); // 点击外部关闭 popup.addEventListener('click', (e) => { if (e.target === popup) { popup.remove(); } }); }; // 收集页面信息 const collectPageInfo = () => { const info = {}; // 1. 概览信息 info.overview = ''; info.overview += '='.repeat(60) + ' 页面概览 ' + '='.repeat(60) + '\n\n'; info.overview += `检查时间: ${new Date().toLocaleString()}\n`; info.overview += `页面URL: ${window.location.href}\n`; info.overview += `域名: ${window.location.hostname}\n`; info.overview += `协议: ${window.location.protocol}\n`; info.overview += `端口: ${window.location.port || '默认'}\n`; info.overview += `路径: ${window.location.pathname}\n`; info.overview += `查询参数: ${window.location.search || '无'}\n`; info.overview += `哈希: ${window.location.hash || '无'}\n\n`; info.overview += `页面标题: ${document.title}\n`; info.overview += `字符编码: ${document.characterSet || document.charset}\n`; info.overview += `文档类型: ${document.doctype ? document.doctype.name : '未知'}\n`; info.overview += `语言: ${document.documentElement.lang || '未设置'}\n\n`; info.overview += `视口尺寸: ${window.innerWidth}×${window.innerHeight}\n`; info.overview += `设备像素比: ${window.devicePixelRatio}\n`; info.overview += `用户代理: ${navigator.userAgent.substring(0, 100)}...\n`; info.overview += `平台: ${navigator.platform}\n`; info.overview += `在线状态: ${navigator.onLine ? '在线' : '离线'}\n`; // 2. Cookie信息 try { const cookies = document.cookie; info.overview += `\nCookie数量: ${cookies ? cookies.split(';').length : 0}\n`; if (cookies) { info.overview += `Cookie内容:\n`; cookies.split(';').forEach((cookie, i) => { info.overview += ` ${i + 1}. ${cookie.trim()}\n`; }); } } catch (e) { info.overview += `\nCookie访问被阻止\n`; } // 3. 元素检查 info.elements = ''; info.elements += '='.repeat(60) + ' 元素检查 ' + '='.repeat(60) + '\n\n'; const elementsToCheck = [ // 常用容器 '#content', '#main', '#container', '#wrapper', '#app', // 图片相关 '#basicExample', '#gallery', '.gallery', '#images', '.images', '#photos', '.photos', '#pictures', '.pictures', '#image-container', '.image-container', '#img-container', '.img-container', '#photo-container', '.photo-container', // 内容相关 '#article', '.article', '#post', '.post', '#entry', '.entry', '#blog', '.blog', '#news', '.news', // 布局相关 '#body', '#page', '#site', '#wrap', '#frame' ]; const foundElements = []; elementsToCheck.forEach(selector => { try { const element = document.querySelector(selector); if (element) { const imgCount = element.querySelectorAll('img').length; const linkCount = element.querySelectorAll('a').length; foundElements.push({ selector, tagName: element.tagName, className: element.className || '无', id: element.id || '无', dimensions: `${element.offsetWidth}×${element.offsetHeight}`, imgCount, linkCount, htmlPreview: element.outerHTML.substring(0, 150) + '...' }); } } catch (e) { // 忽略错误 } }); if (foundElements.length > 0) { info.elements += `找到 ${foundElements.length} 个相关元素:\n\n`; foundElements.forEach((elem, i) => { info.elements += `[${i + 1}] ${elem.selector}\n`; info.elements += ` 元素类型: ${elem.tagName}\n`; info.elements += ` 尺寸: ${elem.dimensions}\n`; info.elements += ` class/id: ${elem.className} / ${elem.id}\n`; info.elements += ` 包含图片: ${elem.imgCount} 张\n`; info.elements += ` 包含链接: ${elem.linkCount} 个\n`; info.elements += ` 代码预览: ${elem.htmlPreview}\n\n`; }); } else { info.elements += '未找到常见容器元素\n'; } // 4. 图片分析 info.images = ''; info.images += '='.repeat(60) + ' 图片分析 ' + '='.repeat(60) + '\n\n'; const allImages = document.querySelectorAll('img'); const imageInfo = []; allImages.forEach((img, index) => { try { const rect = img.getBoundingClientRect(); const parent = img.parentElement; imageInfo.push({ index: index + 1, src: img.src || img.dataset.src || img.currentSrc || '', alt: img.alt || '无', title: img.title || '无', className: img.className || '无', id: img.id || '无', loading: img.loading || 'auto', complete: img.complete, naturalSize: img.naturalWidth > 0 ? `${img.naturalWidth}×${img.naturalHeight}` : '未加载', displaySize: rect.width > 0 ? `${Math.round(rect.width)}×${Math.round(rect.height)}` : '不可见', parent: `${parent.tagName}${parent.id ? '#' + parent.id : ''}${parent.className ? '.' + parent.className.replace(/\s+/g, '.') : ''}`, visible: rect.width > 0 && rect.height > 0 }); } catch (e) { // 忽略错误 } }); info.images += `总图片数: ${allImages.length}\n`; info.images += `可见图片: ${imageInfo.filter(img => img.visible).length}\n`; info.images += `已加载完成: ${imageInfo.filter(img => img.complete).length}\n\n`; info.images += `图片统计 (前20张):\n`; imageInfo.slice(0, 20).forEach(img => { info.images += `\n[${img.index}] `; if (img.src) { const url = new URL(img.src, window.location.href); const shortSrc = url.hostname === window.location.hostname ? url.pathname.substring(0, 40) : url.hostname + url.pathname.substring(0, 20); info.images += `${shortSrc}${img.src.length > 60 ? '...' : ''}\n`; } else { info.images += '无src\n'; } info.images += ` alt/title: ${img.alt} / ${img.title}\n`; info.images += ` class/id: ${img.className} / ${img.id}\n`; info.images += ` 加载状态: ${img.loading} (${img.complete ? '已完成' : '未完成'})\n`; info.images += ` 原始尺寸: ${img.naturalSize}\n`; info.images += ` 显示尺寸: ${img.displaySize}\n`; info.images += ` 父元素: ${img.parent}\n`; info.images += ` 是否可见: ${img.visible ? '✅' : '❌'}\n`; }); // 5. 链接分析 info.links = ''; info.links += '='.repeat(60) + ' 链接分析 ' + '='.repeat(60) + '\n\n'; const allLinks = document.querySelectorAll('a'); const linkInfo = []; allLinks.forEach((link, index) => { try { linkInfo.push({ index: index + 1, href: link.href || '', text: link.textContent.trim().substring(0, 50) || '无文本', title: link.title || '无', target: link.target || '_self', rel: link.rel || '无', download: link.download || '否', isExternal: link.hostname && link.hostname !== window.location.hostname, isAnchor: link.hash && !link.hostname }); } catch (e) { // 忽略错误 } }); info.links += `总链接数: ${allLinks.length}\n`; info.links += `外部链接: ${linkInfo.filter(link => link.isExternal).length}\n`; info.links += `锚点链接: ${linkInfo.filter(link => link.isAnchor).length}\n`; info.links += `下载链接: ${linkInfo.filter(link => link.download !== '否').length}\n\n`; info.links += `链接列表 (前15个):\n`; linkInfo.slice(0, 15).forEach(link => { info.links += `\n[${link.index}] ${link.text}\n`; if (link.href) { const url = new URL(link.href, window.location.href); const displayHref = url.hostname === window.location.hostname ? url.pathname + url.search : url.hostname + url.pathname; info.links += ` 地址: ${displayHref.substring(0, 80)}${link.href.length > 80 ? '...' : ''}\n`; } info.links += ` title: ${link.title}\n`; info.links += ` target: ${link.target}\n`; info.links += ` rel: ${link.rel}\n`; info.links += ` 下载: ${link.download}\n`; info.links += ` 类型: ${link.isExternal ? '外部' : link.isAnchor ? '锚点' : '内部'}\n`; }); // 6. 存储信息 info.storage = ''; info.storage += '='.repeat(60) + ' 存储信息 ' + '='.repeat(60) + '\n\n'; try { // LocalStorage info.storage += 'LocalStorage:\n'; if (localStorage.length > 0) { for (let i = 0; i < localStorage.length; i++) { const key = localStorage.key(i); const value = localStorage.getItem(key); info.storage += ` ${i + 1}. ${key}: ${value.substring(0, 100)}${value.length > 100 ? '...' : ''}\n`; } } else { info.storage += ' 无数据\n'; } // SessionStorage info.storage += '\nSessionStorage:\n'; if (sessionStorage.length > 0) { for (let i = 0; i < sessionStorage.length; i++) { const key = sessionStorage.key(i); const value = sessionStorage.getItem(key); info.storage += ` ${i + 1}. ${key}: ${value.substring(0, 100)}${value.length > 100 ? '...' : ''}\n`; } } else { info.storage += ' 无数据\n'; } } catch (e) { info.storage += `存储访问被阻止: ${e.message}\n`; } // 7. 网络信息 info.network = ''; info.network += '='.repeat(60) + ' 网络信息 ' + '='.repeat(60) + '\n\n'; info.network += `连接类型: ${navigator.connection ? (navigator.connection.effectiveType || '未知') : '未知'}\n`; info.network += `下行速度: ${navigator.connection ? (navigator.connection.downlink || '未知') + ' Mbps' : '未知'}\n`; info.network += `网络延迟: ${navigator.connection ? (navigator.connection.rtt || '未知') + ' ms' : '未知'}\n`; info.network += `数据节省: ${navigator.connection ? (navigator.connection.saveData ? '是' : '否') : '未知'}\n\n`; // 性能信息 info.performance = ''; info.performance += '='.repeat(60) + ' 性能信息 ' + '='.repeat(60) + '\n\n'; if (window.performance && performance.timing) { const timing = performance.timing; info.performance += `页面加载时间: ${timing.loadEventEnd - timing.navigationStart}ms\n`; info.performance += `DOM加载时间: ${timing.domContentLoadedEventEnd - timing.navigationStart}ms\n`; info.performance += `白屏时间: ${timing.responseStart - timing.navigationStart}ms\n`; info.performance += `DNS查询: ${timing.domainLookupEnd - timing.domainLookupStart}ms\n`; info.performance += `TCP连接: ${timing.connectEnd - timing.connectStart}ms\n`; info.performance += `请求响应: ${timing.responseEnd - timing.responseStart}ms\n`; info.performance += `DOM解析: ${timing.domComplete - timing.domInteractive}ms\n`; } else { info.performance += '性能API不可用\n'; } info.performance += `\n内存使用: ${performance.memory ? `已用 ${Math.round(performance.memory.usedJSHeapSize / 1024 / 1024)}MB / 总计 ${Math.round(performance.memory.totalJSHeapSize / 1024 / 1024)}MB` : '不可用'}\n`; // 8. 控制台信息 info.console = ''; info.console += '='.repeat(60) + ' 控制台信息 ' + '='.repeat(60) + '\n\n'; info.console += '这是一个占位符。实际控制台信息需要重写console方法捕获。\n'; info.console += '要查看完整控制台输出,请使用浏览器开发者工具。\n'; return info; }; // 点击事件 inspectBtn.addEventListener('click', function() { const pageInfo = collectPageInfo(); createInspectPopup(pageInfo); }); // 添加到页面 document.body.appendChild(inspectBtn); // 添加样式 const style = document.createElement('style'); style.textContent = ` #page-inspector-btn:hover { background-color: #0056b3 !important; transform: scale(1.05); transition: all 0.2s ease; } #inspector-popup .tab-content::-webkit-scrollbar { width: 8px; height: 8px; } #inspector-popup .tab-content::-webkit-scrollbar-track { background: #f1f1f1; border-radius: 4px; } #inspector-popup .tab-content::-webkit-scrollbar-thumb { background: #888; border-radius: 4px; } #inspector-popup .tab-content::-webkit-scrollbar-thumb:hover { background: #555; } #inspector-popup button[data-tab]:hover { background-color: #3b5168 !important; } `; document.head.appendChild(style); })();