屏蔽百度广告及关键字
// ==UserScript==
// @name 屏蔽百度广告及关键字
// @namespace http://tampermonkey.net/
// @version 3.0.5
// @description 屏蔽百度广告及关键字
// @author linger
// @match https://www.baidu.com/*
// @grant none
// ==/UserScript==
(function () {
'use strict';
window.shieldDebug = false;
window.blackList = {};
let select = document.querySelector.bind(document);
let selectAll = document.querySelectorAll.bind(document);
const $ = (selector, parent) => Array.from((parent || document).querySelector(selector));
const $$ = (selector, parent) => Array.from((parent || document).querySelectorAll(selector));
const _ = createElement;
function createElement(type, data, children, pointer) {
const element = document.createElement(type);
const { id, 'class': className, ...attribute } = data;
if (typeof id === 'string') {
element.id = id;
}
if (Array.isArray(className)) {
element.classList.add(...className);
} else if (typeof className === 'string') {
element.classList.add(className);
}
if (Array.isArray(children)) {
children.forEach(child => {
let result = child;
if (typeof child === 'string') {
result = new Text(child);
}
element.appendChild(result);
});
} else if (typeof children === 'string') {
element.appendChild(new Text(children));
} else if (children) {
element.appendChild(children);
}
for (let name in attribute) {
if (typeof attribute[name] === 'string') {
element.setAttribute(name, attribute[name]);
}
}
pointer && (pointer.element = element);
return element;
}
let selector = {
// 搜索组件
form: '#form.fm',
// 页面容器(通过classList长度判断页面状态)
wrapper: '#wrapper',
// 搜索状态
inSearchWrapper: '.wrapper_s, .wrapper_l',
// 搜索词输入框容器
inputWrapper: '.s_ipt_wr',
// 搜索词输入框
input: '#kw',
// 屏蔽词输入框
delete: '#shield',
// 主体容器
result: '#content_left',
// 右边栏容器
side: '#content_right',
// 右边栏主体
rightList: '#con-ar',
// 大型banner
bigBanner: '#con-at',
// 右边栏登陆提示
loginHint: '.hint_right_middle',
// 提示下载百度app的二维码
qrcode: '.qrcodeCon',
// 相关搜索
rs: '#rs',
// 导航
sTab: '.s_tab_inner',
// 首页左上导航
homeLeft: '#s-top-left',
// 首页底部信息
homeBottom: '#bottom_layer',
// 首页搜索热词
homeHot: '#s-hotsearch-wrapper',
// 首页百度app下载二维码
homeQrcode: '#s_qrcode_nologin',
};
// 初始化,入口方法
function init() {
insert();
console.log('shield');
deleteHomePage();
deleteShieldWords();
deleteUnnecessary();
let result = select(`${selector.result}`);
let first = false;
setInterval(function () {
if (result) {
if (!getComputedStyle(result).height || first) {
first = false;
result = select(`${selector.result}`);
console.log('shield');
deleteUnnecessary();
deleteShieldWords();
}
} else {
first = true;
result = select(`${selector.result}`);
}
}, 200);
}
// 插入屏蔽词输入框,修改样式,监听失焦事件以执行屏蔽操作
function insert() {
let inputWrapper = select(`${selector.inputWrapper}`);
let shieldInput = document.createElement('input');
shieldInput.setAttribute('placeholder', '屏蔽词');
shieldInput.setAttribute('id', 'shield');
shieldInput.setAttribute('autocomplete', 'off');
// 避免焦点移动到搜索输入框
shieldInput.addEventListener('click', function (event) {
event.preventDefault();
event.stopPropagation();
});
shieldInput.addEventListener('blur', deleteShieldWords);
inputWrapper.appendChild(createEditor(shieldWords));
// inputWrapper.appendChild(shieldInput);
beauty();
}
let shieldWords = !localStorage.shieldWords ? [
{ word: '输入后回车或点击加号添加', valid: false, regexp: false, html: false },
{ word: 'debug 屏蔽词开启调试模式', valid: false, regexp: false, html: false },
{ word: 'debug', valid: true, regexp: false, html: false },
{ word: '右侧 .* 按钮开启正则模式', valid: false, regexp: true, html: false },
{ word: '右侧 </> 按钮开启HTML匹配', valid: false, regexp: false, html: true },
{ word: '右侧 x 按钮删除本条屏蔽词', valid: false, regexp: false, html: false },
] : JSON.parse(localStorage.shieldWords);
function newWord(word) {
return {
word,
valid: true,
regexp: false,
html: false,
};
}
function createEditor(data) {
const editor = {};
const content = {};
const wordInput = {};
const addButton = {};
const editButton = {};
const resetButton = {};
_('div', { class: 'editor' },
_('div', { class: ['editor-content', 'editor-content--close'] }, [
_('div', { class: 'editor-item' }, [
_('input', { class: ['editor-input'], type: 'text', placeholder: '屏蔽词' }, [], wordInput),
_('button', { class: ['editor-button', 'editor-block'], type: 'button' }, '+', addButton),
_('button', { class: ['editor-button', 'editor-block'], type: 'button' }, 'E', editButton),
]),
_('div', { class: 'editor-item' }, [
"说明: ",
// _('button', { class: ['editor-button', 'editor-block'], type: 'button' }, ' reset ', resetButton),
_('button', { class: ['editor-button', 'editor-block'], type: 'button' }, '.*'),
"正则; ",
_('button', { class: ['editor-button', 'editor-block'], type: 'button' }, '</>'),
"HTML匹配; ",
_('button', { class: ['editor-button', 'editor-block'], type: 'button' }, 'x'),
"删除; ",
]),
_('div', { class: 'editor-item' }),
].concat(data.map(createEditorItem)), content),
editor,
);
editButton.element.addEventListener('click', function () {
content.element.classList.toggle('editor-content--close');
});
document.body.addEventListener('click', function () {
content.element.classList.add('editor-content--close');
});
// resetButton.element.addEventListener('click', function () {
// localStorage.removeItem('shieldWords');
// window.location.reload();
// });
// 避免回车搜索
wordInput.element.addEventListener('keypress', function (event) {
if (event.key === 'Enter') {
event.preventDefault();
event.stopPropagation();
addButton.element.click();
}
});
addButton.element.addEventListener('click', function (event) {
event.stopPropagation();
if (wordInput.element.value !== '') {
const word = newWord(wordInput.element.value);
data.push(word);
// save data
localStorage.shieldWords = JSON.stringify(data);
content.element.appendChild(createEditorItem(word));
wordInput.element.value = '';
wordInput.element.placeholder = '添加成功';
setTimeout(function () {
wordInput.element.placeholder = '屏蔽词';
}, 2000);
}
deleteShieldWords();
});
content.element.addEventListener('click', function (event) {
event.stopPropagation();
if (event.target.classList.contains('editor-remove')) {
data.splice($$('.editor-remove', content.element).indexOf(event.target), 1);
// save data
localStorage.shieldWords = JSON.stringify(data);
deleteShieldWords();
content.element.removeChild(event.target.parentElement);
} else if (event.target.classList.contains('editor-valid')) {
const index = $$('.editor-valid', content.element).indexOf(event.target);
data[index].valid = event.target.checked;
// save data
localStorage.shieldWords = JSON.stringify(data);
deleteShieldWords();
} else if (event.target.classList.contains('editor-regexp')) {
const index = $$('.editor-regexp', content.element).indexOf(event.target);
data[index].regexp = event.target.checked;
// save data
localStorage.shieldWords = JSON.stringify(data);
deleteShieldWords();
} else if (event.target.classList.contains('editor-html')) {
const index = $$('.editor-html', content.element).indexOf(event.target);
data[index].html = event.target.checked;
// save data
localStorage.shieldWords = JSON.stringify(data);
deleteShieldWords();
}
});
return editor.element;
}
function createEditorItem(data) {
const content = {};
const remove = {};
const item = {};
_('div', { class: 'editor-item', draggable: 'true' }, [
_('label', { class: ['editor-checkbox', 'editor-block'] }, [
_('input', { class: ['editor-checkbox_input', 'editor-valid'], type: 'checkbox', checked: data.valid && 'checked' }),
_('span', { class: 'editor-checkbox_border' }),
]),
_('span', { class: 'editor-word' }, data.word, content),
_('label', { class: ['editor-checkbox', 'editor-block'] }, [
_('input', { class: ['editor-checkbox_input', 'editor-regexp'], type: 'checkbox', checked: data.regexp && 'checked' }),
_('span', { class: 'editor-checkbox_border' }, '.*'),
]),
_('label', { class: ['editor-checkbox', 'editor-block'] }, [
_('input', { class: ['editor-checkbox_input', 'editor-html'], type: 'checkbox', checked: data.html && 'checked' }),
_('span', { class: 'editor-checkbox_border' }, '</>'),
]),
_('button', { class: ['editor-button', 'editor-block', 'editor-remove'], type: 'button' }, 'x', remove),
], item);
return item.element;
}
// 修改样式
function beauty() {
let style = document.createElement('style');
style.innerHTML = `
.s_ipt_wr:not(#up):not(#up):not(#up) {
width: 591px;
height: 44px;
border: 1px solid #c4c7ce;
border-radius: 4px 0 0 4px;
border-right: 0;
overflow: visible;
box-sizing: border-box;
}
#head_wrapper .s_ipt_wr:not(#up):not(#up):not(#up) {
width: 546px;
}
#head_wrapper .s_ipt:not(#up):not(#up):not(#up) {
width: 245px !important;
}
.wrapper_s .s_ipt_wr:not(#up):not(#up):not(#up),
.wrapper_l .s_ipt_wr:not(#up):not(#up):not(#up) {
height: 40px;
}
.s_ipt:not(#up):not(#up):not(#up) {
width: 290px !important;
height: 40px;
margin: 0;
padding: 10px 0 10px 14px !important;
border: 0;
outline: none;
background: transparent;
font: 16px/18px arial;
box-sizing: border-box;
-webkit-appearance: none;
}
.wrapper_s .s_ipt:not(#up):not(#up):not(#up),
.wrapper_l .s_ipt:not(#up):not(#up):not(#up) {
height: 38px;
}
.s_ipt_wr:hover,
.s_ipt_wr.ipthover{border-color:#999 !important}
.s_ipt_wr.iptfocus{border-color:#4e71f2 !important}
.bdsug-new:not(#up):not(#up):not(#up) {
width: 590px;
top: 35px;
border-radius: 0 0 4px 4px;
border: 1px solid #4E6EF2!important;
border-top: 0!important;
box-shadow: none;
font-family: Arial,"PingFang SC","Microsoft YaHei",sans-serif;
z-index: 1;
}
.wrapper_s .bdsug-new:not(#up):not(#up):not(#up),
.wrapper_l .bdsug-new:not(#up):not(#up):not(#up) {
top: 31px;
}
#su{
border-radius: 0 4px 4px 0 !important;
}
#shield {
display: inline-block!important;
width: 150px;
height: 20px;
margin: 10px 0;
padding: 0 0 0 24px;
border: none;
border-left: 1px solid #b6b6b6;
outline: none;
font: 16px/18px arial;
box-sizing: border-box;
vertical-align: top;
}
.wrapper_s #shield,
.wrapper_l #shield{
height: 18px;
}
#lg{
padding-top: 100px;
}
.s-tab-news, .s-tab-video, .s-tab-zhidao, .s-tab-wenku, .s-tab-tieba, .s-tab-b2b, .s-tab-more{
display: none !important;
}
.editor:not(#up):not(#up):not(#up) {
display: inline-block!important;
width: var(--editor-width--close);
height: var(--editor-height);
border-radius: 4px;
vertical-align: top;
--editor-height: 38px;
--editor-width: 300px;
--editor-width--close: 300px;
--editor-offset: 4px;
--editor-block: 20px;
--editor-block-margin-top: calc((var(--editor-height) - var(--editor-block)) / 2 - var(--editor-offset));
--editor-border-default: #b6b6b6;
--editor-border-active: #4a65d2;
--editor-content-background: #ffffff;
}
.editor-content:not(#up):not(#up):not(#up) {
position: relative;
z-index: 9999;
display: flex;
flex-wrap: wrap;
width: calc(var(--editor-width) * 3);
max-height: calc(var(--editor-height) * 8.5);
border-radius: 4px;
outline-width: 1px;
outline-style: solid;
outline-color: var(--editor-border-default);
background-color: var(--editor-content-background);
overflow: scroll;
}
.editor-content--close:not(#up):not(#up):not(#up) {
width: var(--editor-width--close);
height: var(--editor-height);
outline-style: none;
overflow: hidden;
}
.editor-item:not(#up):not(#up):not(#up) {
display: flex;
box-sizing: border-box;
width: var(--editor-width);
height: var(--editor-height);
padding: var(--editor-offset);
line-height: 28px;
overflow: hidden;
vertical-align: top;
}
.editor-item:nth-child(1):not(#up):not(#up):not(#up) {
width: var(--editor-width--close);
}
.editor-input:not(#up):not(#up):not(#up) {
display: inline-block !important;
box-sizing: border-box;
width: calc(100% - (var(--editor-block) + var(--editor-offset) * 2) * 2);
height: 18px;
margin: 6px 4px 0 -4px;
padding-left: 20px;
border: none;
border-left: 1px solid transparent;
outline: none;
font: 16px/18px arial;
vertical-align: top;
}
.editor-content--close > .editor-item:nth-child(1) > .editor-input:not(#up):not(#up):not(#up) {
border-left: 1px solid var(--editor-border-default);
}
.editor-block:not(#up):not(#up):not(#up) {
display: inline-block;
flex-shrink: 0;
min-width: var(--editor-block);
height: var(--editor-block);
margin: var(--editor-block-margin-top) var(--editor-offset) 0;
border-radius: 4px;
vertical-align: top;
}
.editor-checkbox:not(#up):not(#up):not(#up) {
position: relative;
overflow: hidden;
}
.editor-checkbox_input:not(#up):not(#up):not(#up) {
width: calc(var(--editor-block));
height: calc(var(--editor-block));
margin: 0;
vertical-align: top;
}
.editor-checkbox_input:not(#up):not(#up):not(#up) {
-webkit-appearance: checkbox;
}
.editor-checkbox_border:not(#up):not(#up):not(#up) {
position: absolute;
left: 0;
top: 0;
box-sizing: border-box;
width: var(--editor-block);
height: var(--editor-block);
border: 1px solid var(--editor-border-default);
border-radius: 4px;
}
.editor-valid:checked + .editor-checkbox_border:not(#up):not(#up):not(#up) {
border: none;
}
.editor-regexp, .editor-html {
opacity: 0;
}
.editor-regexp + .editor-checkbox_border:not(#up):not(#up):not(#up),
.editor-html + .editor-checkbox_border:not(#up):not(#up):not(#up) {
line-height: var(--editor-block);
text-align: center;
}
.editor-regexp:checked + .editor-checkbox_border:not(#up):not(#up):not(#up),
.editor-html:checked + .editor-checkbox_border:not(#up):not(#up):not(#up) {
border-color: var(--editor-border-active);
color: var(--editor-border-active);
}
.editor-button:not(#up):not(#up):not(#up) {
min-width: var(--editor-block);
padding: 3px;
border: 1px solid var(--editor-border-default);
background-color: transparent;
font-size: 14px;
line-height: 12px;
text-align: center;
}
.editor-button:not(#up):not(#up):not(#up):active {
border-color: var(--editor-border-active);
}
.editor-word:not(#up):not(#up):not(#up) {
width: calc(100% - (var(--editor-block) + var(--editor-offset) * 2) * 3);
overflow: scroll;
white-space: nowrap;
}
.editor-content::-webkit-scrollbar, .editor-word::-webkit-scrollbar {
display: none;
}
`;
let form = select(`${selector.form}`);
form.appendChild(style);
}
// 将节点视觉隐藏,并避免被百度检测到导致广告重新插入页面
function deleteNodeNeverBack(node, type) {
node.setAttribute(`data-${type}`, 'true');
node.style.border = '1px solid crimson';
node.style.background = '#66ccff';
if (!window.shieldDebug) {
node.style.position = 'absolute';
node.style.transform = 'scale(0)';
} else {
node.style.position = 'relative'
node.style.transform = 'scale(1)';
}
}
function showNode(node) {
node.setAttribute('style', '');
}
// 将节点列表全部隐藏
function deleteIt(arr) {
arr.forEach(c => {
deleteNodeNeverBack(c, 'isad');
console.log(['remove', c]);
});
}
// 删除首页多余信息
function deleteHomePage() {
[
selectAll(selector.homeLeft),
selectAll(selector.homeHot),
selectAll(selector.homeBottom),
selectAll(selector.homeQrcode),
].forEach(c => deleteIt(c));
}
// 隐藏广告以及与搜索结果无关的内容
function deleteUnnecessary() {
// 插入搜索结果中的各种广告(广告未被检测插回时,只有普通节点拥有 ${selector.link} 类名)
// 不同类型白名单,可以做成可自行配置的
let whiteList = [
'se_com_default', // 普通结果
'musicsong', // 音乐结果
'tieba_general', 'tieba_offical', 'tieba_star', // 百度贴吧
'bk_polysemy', // 百度百科
'img_address', // 百度图片
'mapdots', // 百度地图
'dict3', 'sp_fanyi', // 百度翻译
/* 小工具模块 */
// 'exrate', // 搜索计算器,进制换算等
// 'exactqa', // 电影,节日信息(百度知识图谱)
// 'exactqa_word', // 百度汉语
/* 小工具模块 */
'ip', // ip工具
'calendar_pc', 'ms_calendar',// 日历
'ms_measures_pc', // 长度换算工具
];
let blackList = [
'sp_realtime_bigpic5', // 实时资讯信息
'edu_link_l', 'jy_course_and_org_pc', // 教育培训机构
'yl_vd_kg_pc', // 影视列表
'short_video_pc', // 视频列表
'se_st_single_video_zhanzhang', // 视频网站推广
'ms_weak_kefu', // 百度安全号码认证平台
'stockweakdemand', 'stockdynamic_moretab', 'stockdynamic', // 股票信息(, 东方财富网, 新浪财经)
'vmp_zxenterprise', // 企业信息
'zp_exact_new', // 百度百聘
'ask_doctor', 'med_disease_kg_collection', 'med_qa',// 百度达尔文计划
];
/**
* 搜索结果广告
*/
// 记录搜索词到 localStorage 关联未知的 tpl 类型
let kw = select(`${selector.input}`).value;
let json = !localStorage.shield ? {} : JSON.parse(localStorage.shield);
let resultADs = Array.from(selectAll(`${selector.result}>div`)).map(c => {
let tpl = c.getAttribute('tpl');
if (tpl) {
json[tpl] = {
kw: kw,
title: c.children[0].innerText.substr(0, 20),
time: new Date().getTime(),
};
}
// 黑名单 tpl 直接隐藏
if (blackList.indexOf(tpl) > -1) {
return c;
}
// 白名单 tpl 一般不处理
else if (whiteList.indexOf(tpl) > -1 || /^ex/.test(tpl)) {
// 白名单中带有推广广告标签的信息隐藏(正常情况下只在 ADBak 之后会有这样的节点)
if (c.innerHTML.indexOf('data-tuiguang') > -1) {
return c;
}
return null;
}
// 保留搜索词勘误提示(无tpl信息)
else if (c.id === 'super_se_tip') {
return null;
}
// 其余全部隐藏但保存tpl供查询
else {
if (tpl && !window.blackList.hasOwnProperty(tpl)) {
window.blackList[tpl] = c;
}
return c;
}
}).filter(c => c);
// 将 tpl 信息保存回 localStorage
localStorage.shield = JSON.stringify(json);
/**
* 右边栏大块广告广告(改版后未验证)
*/
let sideADs = selectAll(`${selector.side}>div`);
/**
* 右边栏各种列表
*/
let topList = [];
if (select(selector.rightList)) {
topList = Array.from(select(selector.rightList).children).map(c => {
let tpl = c.getAttribute('tpl');
if (tpl !== 'right_recommends_merge') {
return c;
} else {
return null;
}
}).filter(c => c);
}
/**
* 隐藏奇怪的东西
*/
let others = [
// 登录提示
selectAll(selector.loginHint),
// 提示下载百度app的二维码
selectAll(selector.qrcode),
// 导航
// selectAll(selector.sTab),
// 相关搜索
selectAll(selector.rs),
// 大型banner
selectAll(selector.bigBanner),
];
[resultADs, sideADs, topList, ...others].forEach(c => deleteIt(c));
}
// 屏蔽主逻辑,屏蔽包含关键词的搜索结果
function clear(type) {
let results = selectAll(`${selector.result}>div`);
results.forEach(c => {
c.setAttribute('data-word', 'false');
});
window.shieldDebug = false;
shieldWords.forEach(function (command) {
if (command.word === 'debug' && command.valid) {
window.shieldDebug = true;
}
});
shieldWords.forEach(function (deleteWord) {
if (deleteWord.valid) {
results.forEach(c => {
if (type === 'hard') {
let str = c.innerText;
if (deleteWord.html) {
str = c.innerHTML;
}
let result;
if (deleteWord.regexp) {
result = new RegExp(deleteWord.word).test(str);
} else {
result = str.indexOf(deleteWord.word) > -1;
}
if (result) {
deleteNodeNeverBack(c, 'word');
console.log(['ignore result', c]);
}
}
});
}
});
results.forEach(c => {
if (c.dataset.word !== 'true' && c.dataset.isad !== 'true') {
showNode(c);
}
});
}
// 执行屏蔽主逻辑,扩展用
function deleteShieldWords() {
clear('hard');
deleteUnnecessary();
}
init();
})();