您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
remove google tracking
当前为
// ==UserScript== // @namespace jp.sceneq.rgtuwaaa // @name remove google tracking UWAA // @description remove google tracking // @description:ja Google追跡UWAAを取り除きなさい // @homepageURL https://github.com/sceneq/RemoveGoogleTracking // @version 0.9 // @include https://www.google.*/* // @grant none // @run-at document-start // @author sceneq // @license MIT // ==/UserScript== 'use strict'; console.time('init'); try { window = window.unsafeWindow || window; } catch (e) {} const yesman = function() { return true; }; const tired = function() {}; /* Return the current Google search mode */ function getParam(parameter, name) { var results = new RegExp('[?&]' + name + '=([^&#]*)').exec(parameter); if (results === null) { return null; } else { return results.pop() || 0; } } /* return search mode */ function getSearchMode() { const parameter = location.search + location.hash; return getParam(parameter, 'tbm') || 'search'; } // matching tracking paramaters const badParametersNamesObj = { base: [ 'biw', // offsetWidth 'bih', // offsetHeight 'ei', 'sa', 'ved', 'source', 'prds', 'bvm', 'bav', 'psi', 'stick', 'dq', 'ech', 'gs_gbg', 'gs_rn', 'cp', 'ictx' ], // image search isch: [ 'scroll', 'vet', 'yv', 'iact', 'forward', 'ndsp', 'csi', 'tbnid' //'docid', // related images //'imgdii', // related images ], searchform: [ // search form 'pbx', 'dpr', 'pf', 'gs_rn', 'gs_mss', 'pq', 'cp', 'oq', 'sclient', 'gs_l', 'aqs' //'gs_ri', // suggestions //'gs_id', // suggestions //'xhr', // suggestions at image search //'tch', // js flag? ], // Google maps maps: ['psi'] }; // search option on first access const GoogleOp = { maps: Symbol(), isch: Symbol(), search: Symbol(), unknown: Symbol() }; const op = (() => { if (location.pathname.startsWith('/maps')) { return GoogleOp.maps; } if (getSearchMode() === 'isch') { return GoogleOp.isch; } else { return GoogleOp.search; } })(); const badParametersNames = (() => { switch (op) { case GoogleOp.maps: return badParametersNamesObj.maps; case GoogleOp.isch: return badParametersNamesObj.base.concat( badParametersNamesObj.searchform, badParametersNamesObj.isch ); case GoogleOp.search: return badParametersNamesObj.base.concat( badParametersNamesObj.searchform ); } })(); const badAttrNamesObj = { default: ['onmousedown', 'ping', 'oncontextmenu'], search: ['onmousedown', 'ping', 'oncontextmenu'], vid: ['onmousedown'], nws: ['onmousedown'], bks: [], isch: [], shop: [] }; // From the nodes selected here, delete parameters specified by badParametersNames const dirtyLinkSelectors = [ // menu 'a.q.qs', // doodle 'a.doodle', // Upper left menu '.gb_Z > a', // Logo 'a#logo', 'div #logocont > a', 'div#qslc > a', 'header#hdr > div > a', // search button? 'form#sf > a', /// imagesearch // colors 'div#sc-block > div > a', // size 'a.hdtb-mitem' ]; const badPaths = ['imgevent', 'shopping\\/product\\/.*?\\/popout']; /* Compile */ // The first paramater is probably 'q' so '?' does not consider const regBadParameters = new RegExp( '&(?:' + badParametersNames.join('|') + ')=.*?(?=(&|$))', 'g' ); const regBadPaths = new RegExp('^/(?:' + badPaths.join('|') + ')'); const dirtyLinkSelector = dirtyLinkSelectors .map(s => s + ":not([href=''])") .join(','); /* Return parameter value */ function extractDirectLink(str, param) { //(?<=q=)(.*)(?=&)/ const res = new RegExp(`[?&]${param}(=([^&#]*))`).exec(str); if (!res || !res[2]) return ''; return decodeURIComponent(res[2]); } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } /* Return Promise when declared the variable name specified by argument */ function onDeclare(obj, propertyStr, interval = 80) { return new Promise(async function(resolve, reject) { const propertyNames = propertyStr.split('.'); let currObj = obj; for (const propertyName of propertyNames) { while (!(propertyName in currObj) || currObj[propertyName] === null) { await sleep(interval); } currObj = currObj[propertyName]; } resolve(currObj); }); } function rewriteProperties(prop) { for (const table of prop) { //const targetObject = typeof table[0] === 'function' ? table[0]() : table[0]; Object.defineProperty(table[0] || {}, table[1], { value: table[2], writable: false }); } } function load() { console.time('LOAD'); /* Overwrite disturbing functions */ rewriteProperties([[window, 'rwt', yesman], [window.gbar_, 'Rm', yesman]]); // do not send referrer const noreferrerMeta = document.createElement('meta'); noreferrerMeta.setAttribute('name', 'referrer'); noreferrerMeta.setAttribute('content', 'no-referrer'); document.querySelector('head').appendChild(noreferrerMeta); /* * Variables */ // Whether to use AJAX const legacy = document.getElementById('cst') === null; /* Nodes */ const nodeMain = document.getElementById('main'); const nodeCnt = document.getElementById('cnt'); const root = (() => { if (legacy) { return nodeCnt || nodeMain || window.document; } else { return nodeMain; // || nodeCnt; } })(); // Flag indicating whether the hard tab is loaded on 'DOMContentLoaded' const lazy_hdtb = !legacy || root === nodeCnt; // Define selector function const $ = root.querySelector.bind(root); const $$ = sel => Array.prototype.slice.call(root.querySelectorAll.call(root, [sel])); // Selector pointing to anchors to purify const dirtySelector = (() => { if (root === window.document) { return 'body a'; } else if (legacy) { return `#${root.id} a`; } else { return '#rcnt a'; } })(); // List of parameters to keep const saveParamNames = [ 'q', 'hl', 'num', 'tbm', 'tbs', 'lr', 'btnI', 'btnK', 'safe' ]; const obstacleInputsSelector = 'form[id*=sf] input' + saveParamNames.map(s => ':not([name=' + s + '])').join(''); /* * Functions */ function removeFormInputs() { for (const node of document.querySelectorAll(obstacleInputsSelector)) { node.parentNode.removeChild(node); } } function removeBadParameters() { for (const dirtyLink of document.querySelectorAll(dirtyLinkSelector)) { dirtyLink.href = dirtyLink.href.replace(regBadParameters, ''); } } const specProcesses = { shop: function() { // Overwrite links(desktop version only) //Object.values(google.pmc.smpo.r).map(s=>{return {title:s[14][0],link:s[28][8]}}) if (legacy) return; onDeclare(google, 'pmc.spop.r').then(shopObj => { const _tempAnchors = $$("div[class$='__content'] a[jsaction='spop.c']"); const [shopAnchors, shopThumbnailAnchors] = [0, 1].map(m => _tempAnchors.filter((_, i) => i % 2 === m) ); const shopArrays = Object.values(shopObj); const shopLinks = shopArrays.map(a => a[34][6]); const zip = rows => rows[0].map((_, c) => rows.map(row => row[c])); if (shopAnchors.length !== shopLinks.length) { console.warn( 'length does not match', shopAnchors.length, shopLinks.length ); return; } for (const detail of zip([ shopAnchors, shopLinks, shopThumbnailAnchors, shopArrays ])) { const [shopAnchor, shopLink, shopThumbnailAnchor, shopArray] = detail; shopAnchor.href = shopThumbnailAnchor.href = shopLink; // Disable click actions //detail[0].__jsaction = null; //detail[0].removeAttribute("jsaction"); // Overwrite variables used when link clicked try { shopArray[3][0][1] = shopLink; shopArray[14][1] = shopLink; shopArray[89][16] = shopLink; shopArray[89][18][0] = shopLink; shopArray[85][3] = shopLink; } catch (e) {} } console.log('Links Rewrited'); }); } }; function removeTracking() { console.time('removeTracking'); const searchMode = getSearchMode(); const badAttrNames = badAttrNamesObj[searchMode] ? badAttrNamesObj[searchMode] : badAttrNamesObj['default']; const directLinkParamName = 'q'; // search result for (const searchResult of $$(dirtySelector)) { // remove attributes for (const badAttrName of badAttrNames) { searchResult.removeAttribute(badAttrName); } // hide referrer searchResult.rel = 'noreferrer'; // remove google redirect link(legacy) if ( searchResult.hasAttribute('href') && searchResult.getAttribute('href').startsWith('/url?') ) { searchResult.href = extractDirectLink( searchResult.href, directLinkParamName ); } searchResult.href = searchResult.href.replace(regBadParameters, ''); } removeBadParameters(); searchMode in specProcesses && specProcesses[searchMode](); console.timeEnd('removeTracking'); } const ObserveOp = { LOADED: { FORM: ['INPUT', 'name', /^oq$/], IMAGE: ['DIV', 'class', /.*irc_bg.*/], HDTB: ['DIV', 'class', /^hdtb-mn-cont$/] }, UPDATE: { HDTB: ['DIV', 'class', /^hdtb-mn-cont$/] }, CHANGE: { HDTB: ['DIV', 'id', /^cnt$/], PAGE: ['DIV', 'data-set', /.+/] } }; const ObserveUntilLoadedList = Object.values(ObserveOp.LOADED); function startObserve(targetElement, op, func, conf = { childList: true }) { if (targetElement === null) { console.warn('targetElement is null', op, func); return; } //console.log(op, 'Register To', targetElement); const targetElementName = op[0]; const targetAttrName = op[1]; const targetAttrValueReg = op[2]; const filterFunc = n => { return ( n.nodeName === targetElementName && targetAttrValueReg.test(n.getAttribute(targetAttrName)) ); }; // if targetElement already appeared if ( ObserveUntilLoadedList.includes(op) && Array.prototype.slice .call(targetElement.querySelectorAll(targetElementName)) .filter(filterFunc).length >= 1 ) { //console.log(op, 'Register To', targetElement); func(); return; } new MutationObserver((mutations, observer) => { const nodes = Array.prototype.concat .apply([], mutations.map(s => Array.prototype.slice.call(s.addedNodes))) //.map((s)=>{console.log(s);return s}) .filter(filterFunc); if (nodes.length >= 1) { //console.log(targetElement, op, 'Fired', nodes[0], func); func(); if (ObserveUntilLoadedList.includes(op)) { observer.disconnect(); } //return startObserve; } }).observe(targetElement, conf); } function pageInit() { removeTracking(); startObserve($('#search'), ObserveOp.CHANGE.PAGE, removeTracking); } const confDeepObserve = { childList: true, subtree: true }; // Remove unnecessary input startObserve( document.querySelector('form'), ObserveOp.LOADED.FORM, removeFormInputs ); // Wait for .hdtb-mn-cont appears in the first page access if (lazy_hdtb && !legacy) { startObserve( root, ObserveOp.LOADED.HDTB, () => { // hdtb loaded switch (getSearchMode()) { case 'isch': // Image Search removeTracking(); // Remove unnecessary script from buttons startObserve($('#isr_mc'), ObserveOp.LOADED.IMAGE, () => { for (const node of $$('a[class*=irc_]')) { node.__jsaction = null; node.removeAttribute('jsaction'); } }); // on search options updated startObserve( $('#top_nav'), ObserveOp.UPDATE.HDTB, removeBadParameters, confDeepObserve ); break; default: pageInit(); // Wait for #cnt inserted. In HDTB switching, since .hdtb-mn-cont does not appear startObserve(root, ObserveOp.CHANGE.HDTB, pageInit); break; } removeFormInputs(); }, confDeepObserve ); } else if (legacy) { removeTracking(); // Remove unnecessary parameters from hdtb const hdtbRoot = $('#hdtbMenus'); if (hdtbRoot) { startObserve(hdtbRoot, ObserveOp.LOADED.HDTB, removeBadParameters); } if (document.getElementById('hdr')) { const stopAddParams = s => { const src = s.srcElement; if (src.nodeName === 'A' && src.href.match(/\/search.*[?&]tbm=isch/)) { s.stopPropagation(); } }; document.addEventListener('click', stopAddParams, true); document.addEventListener('touchStart', stopAddParams, true); } // Remove unnecessary parameters from 'option' for (const option of document.querySelectorAll('#mor > option')) { option.value = option.value.replace(regBadParameters, ''); } console.warn('legacy mode'); console.timeEnd('LOAD'); return; } console.timeEnd('LOAD'); } function init() { onDeclare(window, 'google', 20).then(() => { rewriteProperties([ [google, 'log', yesman], [google, 'logUrl', tired], [google, 'getEI', yesman], [google, 'getLEI', yesman], [google, 'ctpacw', yesman], [google, 'csiReport', yesman], [google, 'report', yesman], [google, 'aft', yesman], [google, 'kEI', '0'] ]); }); // Reject Request by img tag //maps:log204 const regBadImageSrc = /\/(?:(?:gen(?:erate)?|client|fp)_|log)204|(?:metric|csi)\.gstatic\.|(?:adservice)\.(google)/; Object.defineProperty(window.Image.prototype, 'src', { set: function(url) { if (!regBadImageSrc.test(url)) { this.setAttribute('src', url); } } }); // Reject unknown parameters by script tag Object.defineProperty(window.HTMLScriptElement.prototype, 'src', { set: function(url) { this.setAttribute('src', url.replace(regBadParameters, '')); } }); // hook XHR const origOpen = XMLHttpRequest.prototype.open; window.XMLHttpRequest.prototype.open = function(act, path) { if (!regBadPaths.test(path)) { origOpen.apply(this, [act, path.replace(regBadParameters, '')]); } }; // beacon if ('navigator' in window) { const origSendBeacon = navigator.sendBeacon.bind(navigator); navigator.sendBeacon = (path, data) => { if (!regBadImageSrc.test(path)) { origSendBeacon(path, data); } }; } } /* Execute */ init(); console.timeEnd('init'); if ( location.pathname !== '/' && location.pathname !== '/search' && document.querySelector('html').getAttribute('itemtype') !== 'http://schema.org/SearchResultsPage' ) { console.warn(''); return; } window.addEventListener('DOMContentLoaded', load); // for older browser if (document.getElementById('universal') !== null) { load(); }