根据xpath标识广告油猴脚本|屏蔽广告
作者:YXN-js 阅读量:159 发布日期:2025-02-26
localStorage版
// ==UserScript==
// @name XPath元素阻止程序_localStorage版
// @namespace http://tampermonkey.net/
// @version 2.0
// @description localStorage版元素屏蔽工具,支持XPath规则管理
// @author YXN
// @match *://*/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// 生成网站专属存储键名
const storageKey = `xpath_blocker_${location.hostname}`;
// 样式增强
const css = `
#blocker-btn {
position: fixed;
bottom: 30px;
right: 30px;
z-index: 2147483647;
width: 45px;
height: 45px;
border-radius: 50%;
background: #2196F3;
color: white;
border: none;
cursor: pointer;
box-shadow: 0 3px 6px rgba(0,0,0,0.16);
font-size: 20px;
transition: transform 0.2s;
}
.blocker-dialog {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 8px 24px rgba(0,0,0,0.2);
z-index: 2147483646;
min-width: 320px;
}
.rule-item {
display: flex;
align-items: center;
padding: 8px;
border-bottom: 1px solid #eee;
}
.rule-index {
width: 30px;
color: #666;
}
.rule-text {
flex: 1;
font-family: monospace;
overflow-x: auto;
}
.delete-btn {
color: #f44336;
cursor: pointer;
margin-left: 10px;
}
`;
// 注入全局样式
const style = document.createElement('style');
style.textContent = css;
document.head.appendChild(style);
class BlockerSystem {
constructor() {
this.rules = this.loadRules();
this.initUI();
this.setupObserver();
}
// 从localStorage加载规则
loadRules() {
try {
return JSON.parse(localStorage.getItem(storageKey)) || [];
} catch {
return [];
}
}
// 保存规则到localStorage
saveRules() {
localStorage.setItem(storageKey, JSON.stringify(this.rules));
}
// 初始化界面
initUI() {
this.createButton();
this.applyRules();
}
// 创建悬浮按钮
createButton() {
this.btn = document.createElement('button');
this.btn.id = 'blocker-btn';
this.btn.textContent = '✖';
this.btn.addEventListener('click', () => this.showMainDialog());
document.body.appendChild(this.btn);
}
// 显示主对话框
showMainDialog() {
const dialog = document.createElement('div');
dialog.className = 'blocker-dialog';
dialog.innerHTML = `
<h3>元素屏蔽系统</h3>
<div style="margin:15px 0">
<button id="add-rule">➕ 添加新规则</button>
<button id="manage-rules">???? 管理规则</button>
</div>
`;
dialog.querySelector('#add-rule').addEventListener('click', () => this.showAddDialog());
dialog.querySelector('#manage-rules').addEventListener('click', () => this.showRuleManager());
this.showModal(dialog);
}
// 显示添加规则对话框
showAddDialog() {
const dialog = document.createElement('div');
dialog.className = 'blocker-dialog';
dialog.innerHTML = `
<h3>添加XPath规则</h3>
<textarea
id="xpath-input"
placeholder="输入XPath表达式(每行一个规则)"
style="width:100%; height:100px; margin:10px 0"
></textarea>
<div style="text-align:right">
<button class="cancel">取消</button>
<button class="confirm">保存</button>
</div>
`;
dialog.querySelector('.cancel').addEventListener('click', () => dialog.remove());
dialog.querySelector('.confirm').addEventListener('click', () => {
const input = dialog.querySelector('textarea').value;
this.addRules(input.split('\n').map(x => x.trim()).filter(x => x));
dialog.remove();
this.applyRules();
});
this.showModal(dialog);
}
// 显示规则管理器
showRuleManager() {
const dialog = document.createElement('div');
dialog.className = 'blocker-dialog';
dialog.innerHTML = `
<h3>已保存规则(共${this.rules.length}条)</h3>
<div id="rule-list" style="max-height:300px;overflow-y:auto;margin:10px 0"></div>
<div style="text-align:right">
<button class="cancel">关闭</button>
</div>
`;
const listContainer = dialog.querySelector('#rule-list');
this.rules.forEach((rule, index) => {
const item = document.createElement('div');
item.className = 'rule-item';
item.innerHTML = `
<div class="rule-index">${index + 1}.</div>
<div class="rule-text">${rule}</div>
<div class="delete-btn" data-index="${index}">????️</div>
`;
item.querySelector('.delete-btn').addEventListener('click', (e) => {
const index = parseInt(e.target.dataset.index);
this.deleteRule(index);
item.remove();
});
listContainer.appendChild(item);
});
dialog.querySelector('.cancel').addEventListener('click', () => dialog.remove());
this.showModal(dialog);
}
// 显示模态框
showModal(content) {
const overlay = document.createElement('div');
overlay.style = `
position:fixed;
top:0;
left:0;
width:100%;
height:100%;
background:rgba(0,0,0,0.5);
z-index:2147483645;
`;
overlay.appendChild(content);
overlay.addEventListener('click', (e) => {
if (e.target === overlay) overlay.remove();
});
document.body.appendChild(overlay);
}
// 添加新规则
addRules(newRules) {
newRules.forEach(rule => {
if (!this.rules.includes(rule)) {
this.rules.push(rule);
}
});
this.saveRules();
}
// 删除单条规则
deleteRule(index) {
if (index >= 0 && index < this.rules.length) {
this.rules.splice(index, 1);
this.saveRules();
this.applyRules();
}
}
// 应用所有规则
applyRules() {
this.rules.forEach(rule => {
try {
const nodes = document.evaluate(
rule,
document,
null,
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
null
);
for (let i = 0; i < nodes.snapshotLength; i++) {
const node = nodes.snapshotItem(i);
node.style.display = 'none';
}
} catch (e) {
console.warn(`无效的XPath规则: ${rule}`, e);
}
});
}
// 设置DOM监听
setupObserver() {
new MutationObserver(() => {
this.applyRules();
}).observe(document, {
childList: true,
subtree: true
});
}
}
// 初始化系统
new BlockerSystem();
})();
GM存储版
// ==UserScript==
// @name XPath元素阻止程序_GM存储版
// @namespace http://tampermonkey.net/
// @version 1.3
// @description 支持GM存储和规则管理的元素屏蔽工具
// @author YourName
// @match *://*/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_registerMenuCommand
// @grant GM_addStyle
// ==/UserScript==
(function() {
'use strict';
// 生成网站唯一键名
const getSiteKey = () => `xpath_rules_${location.hostname}`;
// 样式配置
GM_addStyle(`
#blocker-btn {
position: fixed;
bottom: 30px;
right: 30px;
z-index: 2147483647;
width: 45px;
height: 45px;
border-radius: 50%;
background: #2196F3;
color: white;
border: none;
cursor: pointer;
box-shadow: 0 3px 6px rgba(0,0,0,0.16);
font-size: 20px;
transition: transform 0.2s;
}
#blocker-btn:hover {
transform: scale(1.1);
}
.blocker-dialog {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 8px 24px rgba(0,0,0,0.2);
z-index: 2147483646;
min-width: 320px;
}
.blocker-textarea {
width: 100%;
height: 120px;
margin: 12px 0;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
resize: vertical;
}
.blocker-btns {
display: flex;
gap: 8px;
justify-content: flex-end;
}
.blocker-btn {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
}
.blocker-confirm {
background: #4CAF50;
color: white;
}
.blocker-cancel {
background: #f44336;
color: white;
}
`);
class ElementBlocker {
constructor() {
this.rules = GM_getValue(getSiteKey(), []);
this.observer = null;
this.init();
}
init() {
// 初始化界面
this.createButton();
// 应用现有规则
this.applyRules();
// 监听动态内容
this.setupMutationObserver();
// 注册管理命令
GM_registerMenuCommand('管理屏蔽规则', () => this.showRuleManager());
}
createButton() {
this.btn = document.createElement('button');
this.btn.id = 'blocker-btn';
this.btn.textContent = '⛔';
this.btn.addEventListener('click', () => this.showDialog());
document.body.appendChild(this.btn);
}
showDialog() {
if (this.dialog) return;
this.dialog = document.createElement('div');
this.dialog.className = 'blocker-dialog';
this.dialog.innerHTML = `
<h3 style="margin:0 0 15px">元素屏蔽器</h3>
<textarea class="blocker-textarea"
placeholder="输入要屏蔽的XPath表达式(每行一个)"></textarea>
<div class="blocker-btns">
<button class="blocker-btn blocker-cancel">取消</button>
<button class="blocker-btn blocker-confirm">确定</button>
</div>
`;
// 事件绑定
this.dialog.querySelector('.blocker-cancel').addEventListener('click', () => this.closeDialog());
this.dialog.querySelector('.blocker-confirm').addEventListener('click', () => {
const textarea = this.dialog.querySelector('textarea');
this.processInput(textarea.value);
this.closeDialog();
});
document.body.appendChild(this.dialog);
}
closeDialog() {
this.dialog.remove();
this.dialog = null;
}
processInput(input) {
const newRules = input.split('\n')
.map(x => x.trim())
.filter(x => x.length > 0);
if (newRules.length > 0) {
this.rules = [...new Set([...this.rules, ...newRules])];
this.saveRules();
this.applyRules();
}
}
applyRules() {
this.rules.forEach(rule => {
try {
const nodes = document.evaluate(
rule,
document,
null,
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
null
);
for (let i = 0; i < nodes.snapshotLength; i++) {
const node = nodes.snapshotItem(i);
if (node) node.style.display = 'none';
}
} catch (e) {
console.warn(`无效的XPath规则: ${rule}`, e);
}
});
}
saveRules() {
GM_setValue(getSiteKey(), this.rules);
}
setupMutationObserver() {
this.observer = new MutationObserver(mutations => {
let shouldUpdate = false;
mutations.forEach(mutation => {
if (mutation.addedNodes.length > 0) shouldUpdate = true;
});
if (shouldUpdate) this.applyRules();
});
this.observer.observe(document, {
childList: true,
subtree: true
});
}
showRuleManager() {
const manager = document.createElement('div');
manager.className = 'blocker-dialog';
manager.innerHTML = `
<h3 style="margin:0 0 15px">当前屏蔽规则 (${this.rules.length}条)</h3>
<div style="max-height: 300px; overflow-y: auto; margin-bottom: 15px">
${this.rules.map((rule, index) => `
<div style="padding: 8px; border-bottom: 1px solid #eee;">
<span style="color:#666">${index + 1}.</span>
<code>${rule}</code>
</div>
`).join('')}
</div>
<div class="blocker-btns">
<button class="blocker-btn blocker-cancel">关闭</button>
<button class="blocker-btn" style="background:#ff9800"
id="delete-rule">删除规则</button>
</div>
`;
// 事件绑定
manager.querySelector('.blocker-cancel').addEventListener('click', () => manager.remove());
manager.querySelector('#delete-rule').addEventListener('click', () => {
const index = prompt('请输入要删除的规则编号(列表中的数字):');
const num = parseInt(index) - 1;
if (!isNaN(num) && num >= 0 && num < this.rules.length) {
this.rules.splice(num, 1);
this.saveRules();
this.applyRules();
alert(`已删除第 ${num + 1} 条规则`);
manager.remove();
} else {
alert('无效的编号输入');
}
});
document.body.appendChild(manager);
}
}
// 启动脚本
new ElementBlocker();
})();
YXN-js
2025-02-26