一个轻量级的用户脚本,可帮助您快速提取网页上的文本内容。通过简单的点击操作,即可查看、复制或深入提取嵌套文本内容。
当前为
// ==UserScript==
// @name 文本提取助手
// @namespace http://tampermonkey.net/
// @version 2.1
// @description 一个轻量级的用户脚本,可帮助您快速提取网页上的文本内容。通过简单的点击操作,即可查看、复制或深入提取嵌套文本内容。
// @license MIT
// @author niweizhuan
// @match *://*/*
// @grant GM_setClipboard
// @grant GM_notification
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_addStyle
// @grant GM_registerMenuCommand
// ==/UserScript==
(function() {
'use strict';
// 检查是否被禁用
if (GM_getValue('scriptDisabled', false)) {
return;
}
// 添加自定义样式
GM_addStyle(`
#text-copier-container {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 9999;
display: flex;
flex-direction: column;
gap: 10px;
align-items: flex-end;
}
#text-copier-main-btn {
padding: 8px 16px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
}
#text-copier-delete-btn {
padding: 4px 8px;
background-color: #f44336;
color: white;
border: none;
border-radius: 50%;
cursor: pointer;
width: 24px;
height: 24px;
display: flex;
justify-content: center;
align-items: center;
font-size: 16px;
}
#text-copier-modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 10000;
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
max-width: 80%;
max-height: 80vh;
display: flex;
flex-direction: column;
min-width: 300px;
/* 新增响应式控制 */
max-width: 90vw;
max-height: 80vh;
width: auto;
min-width: 300px;
overflow: hidden;
display: flex;
flex-direction: column;
}
#text-copier-modal-content {
flex: 1;
overflow-y: auto;
margin-bottom: 15px;
padding: 10px;
border: 1px solid #eee;
border-radius: 4px;
white-space: pre-wrap;
word-break: break-word;
flex: 1;
max-height: 60vh;
/* 添加漂亮的滚动条 */
scrollbar-width: thin;
scrollbar-color: #4CAF50 #f1f1f1;
}
#text-copier-modal-footer {
display: flex;
justify-content: space-between;
gap: 10px;
}
.text-copier-modal-btn {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
flex: 1;
}
#text-copier-copy-btn {
background-color: #4CAF50;
color: white;
}
#text-copier-next-btn {
background-color: #2196F3;
color: white;
}
#text-copier-close-btn {
background-color: #f44336;
color: white;
}
.text-copier-highlight {
outline: 2px dashed #FF9800;
outline-offset: 2px;
background-color: rgba(255, 152, 0, 0.1);
}
#text-copier-modal-content::-webkit-scrollbar {
width: 8px;
}
#text-copier-modal-content::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4px;
}
#text-copier-modal-content::-webkit-scrollbar-thumb {
background-color: #4CAF50;
border-radius: 4px;
}
`);
// 注册(不可用)菜单命令
GM_registerMenuCommand("切换文本获取工具状态", function() {
const currentState = GM_getValue('scriptDisabled', false);
GM_setValue('scriptDisabled', !currentState);
if (!currentState) {
showNotification('文本获取工具已禁用 - 将在下次页面加载时生效');
// 立即隐藏界面
const container = document.getElementById('text-copier-container');
if (container) container.style.display = 'none';
} else {
showNotification('文本获取工具已启用 - 将在下次页面加载时生效');
// 立即显示界面
const container = document.getElementById('text-copier-container');
if (container) container.style.display = 'flex';
}
});
// 创建主按钮容器
const buttonContainer = document.createElement('div');
buttonContainer.id = 'text-copier-container';
// 创建主按钮
const mainButton = document.createElement('button');
mainButton.id = 'text-copier-main-btn';
mainButton.textContent = '获取文本';
// 创建删除按钮
const deleteButton = document.createElement('button');
deleteButton.id = 'text-copier-delete-btn';
deleteButton.textContent = '×';
deleteButton.title = '隐藏按钮(直到下次打开浏览器)';
// 将元素添加到容器和页面
buttonContainer.appendChild(deleteButton);
buttonContainer.appendChild(mainButton);
document.body.appendChild(buttonContainer);
// 创建模态框
const modal = document.createElement('div');
modal.id = 'text-copier-modal';
modal.style.display = 'none';
const modalContent = document.createElement('div');
modalContent.id = 'text-copier-modal-content';
const modalFooter = document.createElement('div');
modalFooter.id = 'text-copier-modal-footer';
const copyButton = document.createElement('button');
copyButton.id = 'text-copier-copy-btn';
copyButton.textContent = '复制';
const nextButton = document.createElement('button');
nextButton.id = 'text-copier-next-btn';
nextButton.textContent = '下一层';
const closeButton = document.createElement('button');
closeButton.id = 'text-copier-close-btn';
closeButton.textContent = '关闭';
modalFooter.appendChild(copyButton);
modalFooter.appendChild(nextButton);
modalFooter.appendChild(closeButton);
modal.appendChild(modalContent);
modal.appendChild(modalFooter);
document.body.appendChild(modal);
let isSelecting = false;
let currentElement = null;
let clickHistory = [];
// 主按钮点击事件
mainButton.addEventListener('click', function(e) {
e.stopPropagation();
if (!isSelecting) {
// 进入选择模式
isSelecting = true;
mainButton.textContent = '取消选择';
mainButton.style.backgroundColor = '#f44336';
// 添加高亮样式
document.body.style.cursor = 'pointer';
document.querySelectorAll('*').forEach(el => {
el.style.cursor = 'pointer';
});
} else {
// 取消选择模式
exitSelectionMode();
}
});
// 删除按钮点击事件
deleteButton.addEventListener('click', function(e) {
e.stopPropagation();
buttonContainer.style.display = 'none';
GM_setValue('buttonHidden', true);
showNotification('获取文本按钮已隐藏');
if (currentElement) {
currentElement.classList.remove('text-copier-highlight');
}
});
// 复制按钮点击事件
copyButton.addEventListener('click', function() {
const text = modalContent.textContent;
if (text && text !== '未找到文本内容') {
try {
if (typeof GM_setClipboard !== 'undefined') {
GM_setClipboard(text);
showNotification('复制成功', 'success');
} else {
navigator.clipboard.writeText(text).then(() => {
showNotification('复制成功', 'success');
}).catch(err => {
console.error('复制失败:', err);
showNotification('复制失败: ' + err.message, 'error');
});
}
// 复制成功后1秒移除高亮
if (currentElement) {
setTimeout(() => {
currentElement.classList.remove('text-copier-highlight');
}, 1000);
}
} catch (err) {
console.error('复制失败:', err);
showNotification('复制失败: ' + err.message, 'error');
}
} else {
showNotification('没有可复制的文本内容', 'warning');
}
});
// 下一层按钮点击事件
nextButton.addEventListener('click', function() {
if (!currentElement) return;
// 先移除旧元素的高亮
currentElement.classList.remove('text-copier-highlight');
// 查找下一个元素
const children = Array.from(currentElement.children);
let nextElement = null;
for (const child of children) {
if (hasVisibleText(child)) {
nextElement = child;
break;
}
}
if (nextElement) {
currentElement = nextElement;
showElementText(currentElement);
} else {
showNotification('已到达最底层');
// 如果没有下层了,1秒后移除当前高亮
setTimeout(() => {
if (currentElement) {
currentElement.classList.remove('text-copier-highlight');
}
}, 1000);
}
});
// 关闭按钮点击事件
closeButton.addEventListener('click', function() {
modal.style.display = 'none';
if (currentElement) {
currentElement.classList.remove('text-copier-highlight');
currentElement = null;
}
clickHistory = [];
});
// 显示通知
function showNotification(message, type = 'info') {
// 移除之前的通知
const oldNotification = document.getElementById('text-copier-custom-notification');
if (oldNotification) oldNotification.remove();
// 创建新通知
const notification = document.createElement('div');
notification.id = 'text-copier-custom-notification';
notification.textContent = message;
notification.style.position = 'fixed';
notification.style.bottom = '20px';
notification.style.left = '50%';
notification.style.transform = 'translateX(-50%)';
notification.style.padding = '10px 20px';
notification.style.borderRadius = '4px';
notification.style.zIndex = '10000';
notification.style.transition = 'opacity 0.3s';
notification.style.maxWidth = '80%';
notification.style.textAlign = 'center';
// 根据类型设置样式
switch(type) {
case 'success':
notification.style.backgroundColor = '#4CAF50';
notification.style.color = 'white';
break;
case 'error':
notification.style.backgroundColor = '#f44336';
notification.style.color = 'white';
break;
case 'warning':
notification.style.backgroundColor = '#FF9800';
notification.style.color = 'white';
break;
default:
notification.style.backgroundColor = '#2196F3';
notification.style.color = 'white';
}
document.body.appendChild(notification);
// 自动消失
setTimeout(() => {
notification.style.opacity = '0';
setTimeout(() => notification.remove(), 300);
}, 300);
}
// 检查元素是否有可见文本
function hasVisibleText(element) {
if (!element) return false;
// 检查元素是否可见
const style = window.getComputedStyle(element);
if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') {
return false;
}
// 检查是否有直接文本内容
if (element.textContent.trim()) {
return true;
}
// 检查是否有子元素包含文本
for (const child of element.children) {
if (hasVisibleText(child)) {
return true;
}
}
return false;
}
// 显示元素的文本内容
function showElementText(element) {
if (!element) return;
// 移除之前的高亮
if (currentElement) {
currentElement.classList.remove('text-copier-highlight');
}
currentElement = element;
currentElement.classList.add('text-copier-highlight');
// 获取文本内容(限制最大长度)
let text = element.textContent.trim();
// 如果文本为空,尝试获取其他属性
if (!text) {
text = element.value || element.getAttribute('placeholder') ||
element.getAttribute('aria-label') || element.getAttribute('title') || '';
text = text.trim();
}
// 显示在模态框中
modalContent.textContent = text || '未找到文本内容';
modal.style.display = 'block';
// 记录点击历史
clickHistory.push({
element: element,
position: getElementPosition(element),
text: text
});
}
// 获取元素在页面中的位置
function getElementPosition(element) {
const rect = element.getBoundingClientRect();
return {
x: rect.left + window.scrollX,
y: rect.top + window.scrollY,
width: rect.width,
height: rect.height
};
}
// 退出选择模式
function exitSelectionMode() {
isSelecting = false;
mainButton.textContent = '获取文本';
mainButton.style.backgroundColor = '#4CAF50';
// 恢复光标样式
document.body.style.cursor = '';
document.querySelectorAll('*').forEach(el => {
el.style.cursor = '';
});
}
// 页面点击事件处理
document.addEventListener('click', function(e) {
if (!isSelecting) return;
// 如果点击的是我们的按钮或模态框,则不处理
if (e.target.closest('#text-copier-container') || e.target.closest('#text-copier-modal')) {
return;
}
e.preventDefault();
e.stopPropagation();
// 获取点击元素
const target = e.target;
showElementText(target);
// 退出选择模式
exitSelectionMode();
}, true);
})();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址