// ==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(); })();