You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
522 lines
22 KiB
522 lines
22 KiB
// ==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);
|
|
})(); |