ant-baidu-adv

百度广告反制

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name          ant-baidu-adv
// @version       0.1.0
// @namespace     wings-j.cn
// @description   百度广告反制
// @author        WingsJ
// @match         https://www.baidu.com/*
// @icon          https://www.google.com/s2/favicons?domain=baidu.com
// @license MIT
// ==/UserScript==

(function () {
  'use strict';

  var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
  /*
   * Copyright 2012 The Polymer Authors. All rights reserved.
   * Use of this source code is goverened by a BSD-style
   * license that can be found in the LICENSE file.
   */

  var WeakMap = window.WeakMap;

  if (typeof WeakMap === 'undefined') {
    var defineProperty = Object.defineProperty;
    var counter = Date.now() % 1e9;

    WeakMap = function WeakMap() {
      this.name = '__st' + (Math.random() * 1e9 >>> 0) + (counter++ + '__');
    };

    WeakMap.prototype = {
      set: function set(key, value) {
        var entry = key[this.name];
        if (entry && entry[0] === key) entry[1] = value;else defineProperty(key, this.name, {
          value: [key, value],
          writable: true
        });
        return this;
      },
      get: function get(key) {
        var entry;
        return (entry = key[this.name]) && entry[0] === key ? entry[1] : undefined;
      },
      'delete': function _delete(key) {
        var entry = key[this.name];
        if (!entry) return false;
        var hasValue = entry[0] === key;
        entry[0] = entry[1] = undefined;
        return hasValue;
      },
      has: function has(key) {
        var entry = key[this.name];
        if (!entry) return false;
        return entry[0] === key;
      }
    };
  }

  var registrationsTable = new WeakMap(); // We use setImmediate or postMessage for our future callback.

  var setImmediate = window.msSetImmediate; // Use post message to emulate setImmediate.

  if (!setImmediate) {
    var setImmediateQueue = [];
    var sentinel = String(Math.random());
    window.addEventListener('message', function (e) {
      if (e.data === sentinel) {
        var queue = setImmediateQueue;
        setImmediateQueue = [];
        queue.forEach(function (func) {
          func();
        });
      }
    });

    setImmediate = function setImmediate(func) {
      setImmediateQueue.push(func);
      window.postMessage(sentinel, '*');
    };
  } // This is used to ensure that we never schedule 2 callas to setImmediate


  var isScheduled = false; // Keep track of observers that needs to be notified next time.

  var scheduledObservers = [];
  /**
   * Schedules |dispatchCallback| to be called in the future.
   * @param {MutationObserver} observer
   */

  function scheduleCallback(observer) {
    scheduledObservers.push(observer);

    if (!isScheduled) {
      isScheduled = true;
      setImmediate(dispatchCallbacks);
    }
  }

  function wrapIfNeeded(node) {
    return window.ShadowDOMPolyfill && window.ShadowDOMPolyfill.wrapIfNeeded(node) || node;
  }

  function dispatchCallbacks() {
    // http://dom.spec.whatwg.org/#mutation-observers
    isScheduled = false; // Used to allow a new setImmediate call above.

    var observers = scheduledObservers;
    scheduledObservers = []; // Sort observers based on their creation UID (incremental).

    observers.sort(function (o1, o2) {
      return o1.uid_ - o2.uid_;
    });
    var anyNonEmpty = false;
    observers.forEach(function (observer) {
      // 2.1, 2.2
      var queue = observer.takeRecords(); // 2.3. Remove all transient registered observers whose observer is mo.

      removeTransientObserversFor(observer); // 2.4

      if (queue.length) {
        observer.callback_(queue, observer);
        anyNonEmpty = true;
      }
    }); // 3.

    if (anyNonEmpty) dispatchCallbacks();
  }

  function removeTransientObserversFor(observer) {
    observer.nodes_.forEach(function (node) {
      var registrations = registrationsTable.get(node);
      if (!registrations) return;
      registrations.forEach(function (registration) {
        if (registration.observer === observer) registration.removeTransientObservers();
      });
    });
  }
  /**
   * This function is used for the "For each registered observer observer (with
   * observer's options as options) in target's list of registered observers,
   * run these substeps:" and the "For each ancestor ancestor of target, and for
   * each registered observer observer (with options options) in ancestor's list
   * of registered observers, run these substeps:" part of the algorithms. The
   * |options.subtree| is checked to ensure that the callback is called
   * correctly.
   *
   * @param {Node} target
   * @param {function(MutationObserverInit):MutationRecord} callback
   */


  function forEachAncestorAndObserverEnqueueRecord(target, callback) {
    for (var node = target; node; node = node.parentNode) {
      var registrations = registrationsTable.get(node);

      if (registrations) {
        for (var j = 0; j < registrations.length; j++) {
          var registration = registrations[j];
          var options = registration.options; // Only target ignores subtree.

          if (node !== target && !options.subtree) continue;
          var record = callback(options);
          if (record) registration.enqueue(record);
        }
      }
    }
  }

  var uidCounter = 0;
  /**
   * The class that maps to the DOM MutationObserver interface.
   * @param {Function} callback.
   * @constructor
   */

  function JsMutationObserver(callback) {
    this.callback_ = callback;
    this.nodes_ = [];
    this.records_ = [];
    this.uid_ = ++uidCounter;
  }

  JsMutationObserver.prototype = {
    observe: function observe(target, options) {
      target = wrapIfNeeded(target); // 1.1

      if (!options.childList && !options.attributes && !options.characterData || // 1.2
      options.attributeOldValue && !options.attributes || // 1.3
      options.attributeFilter && options.attributeFilter.length && !options.attributes || // 1.4
      options.characterDataOldValue && !options.characterData) {
        throw new SyntaxError();
      }

      var registrations = registrationsTable.get(target);
      if (!registrations) registrationsTable.set(target, registrations = []); // 2
      // If target's list of registered observers already includes a registered
      // observer associated with the context object, replace that registered
      // observer's options with options.

      var registration;

      for (var i = 0; i < registrations.length; i++) {
        if (registrations[i].observer === this) {
          registration = registrations[i];
          registration.removeListeners();
          registration.options = options;
          break;
        }
      } // 3.
      // Otherwise, add a new registered observer to target's list of registered
      // observers with the context object as the observer and options as the
      // options, and add target to context object's list of nodes on which it
      // is registered.


      if (!registration) {
        registration = new Registration(this, target, options);
        registrations.push(registration);
        this.nodes_.push(target);
      }

      registration.addListeners();
    },
    disconnect: function disconnect() {
      this.nodes_.forEach(function (node) {
        var registrations = registrationsTable.get(node);

        for (var i = 0; i < registrations.length; i++) {
          var registration = registrations[i];

          if (registration.observer === this) {
            registration.removeListeners();
            registrations.splice(i, 1); // Each node can only have one registered observer associated with
            // this observer.

            break;
          }
        }
      }, this);
      this.records_ = [];
    },
    takeRecords: function takeRecords() {
      var copyOfRecords = this.records_;
      this.records_ = [];
      return copyOfRecords;
    }
  };
  /**
   * @param {string} type
   * @param {Node} target
   * @constructor
   */

  function MutationRecord(type, target) {
    this.type = type;
    this.target = target;
    this.addedNodes = [];
    this.removedNodes = [];
    this.previousSibling = null;
    this.nextSibling = null;
    this.attributeName = null;
    this.attributeNamespace = null;
    this.oldValue = null;
  }

  function copyMutationRecord(original) {
    var record = new MutationRecord(original.type, original.target);
    record.addedNodes = original.addedNodes.slice();
    record.removedNodes = original.removedNodes.slice();
    record.previousSibling = original.previousSibling;
    record.nextSibling = original.nextSibling;
    record.attributeName = original.attributeName;
    record.attributeNamespace = original.attributeNamespace;
    record.oldValue = original.oldValue;
    return record;
  }

  var currentRecord, recordWithOldValue;
  /**
   * Creates a record without |oldValue| and caches it as |currentRecord| for
   * later use.
   * @param {string} oldValue
   * @return {MutationRecord}
   */

  function getRecord(type, target) {
    return currentRecord = new MutationRecord(type, target);
  }
  /**
   * Gets or creates a record with |oldValue| based in the |currentRecord|
   * @param {string} oldValue
   * @return {MutationRecord}
   */


  function getRecordWithOldValue(oldValue) {
    if (recordWithOldValue) return recordWithOldValue;
    recordWithOldValue = copyMutationRecord(currentRecord);
    recordWithOldValue.oldValue = oldValue;
    return recordWithOldValue;
  }

  function clearRecords() {
    currentRecord = recordWithOldValue = undefined;
  }
  /**
   * @param {MutationRecord} record
   * @return {boolean} Whether the record represents a record from the current
   * mutation event.
   */


  function recordRepresentsCurrentMutation(record) {
    return record === recordWithOldValue || record === currentRecord;
  }
  /**
   * Selects which record, if any, to replace the last record in the queue.
   * This returns |null| if no record should be replaced.
   *
   * @param {MutationRecord} lastRecord
   * @param {MutationRecord} newRecord
   * @param {MutationRecord}
   */


  function selectRecord(lastRecord, newRecord) {
    if (lastRecord === newRecord) return lastRecord; // Check if the the record we are adding represents the same record. If
    // so, we keep the one with the oldValue in it.

    if (recordWithOldValue && recordRepresentsCurrentMutation(lastRecord)) return recordWithOldValue;
    return null;
  }
  /**
   * Class used to represent a registered observer.
   * @param {MutationObserver} observer
   * @param {Node} target
   * @param {MutationObserverInit} options
   * @constructor
   */


  function Registration(observer, target, options) {
    this.observer = observer;
    this.target = target;
    this.options = options;
    this.transientObservedNodes = [];
  }

  Registration.prototype = {
    enqueue: function enqueue(record) {
      var records = this.observer.records_;
      var length = records.length; // There are cases where we replace the last record with the new record.
      // For example if the record represents the same mutation we need to use
      // the one with the oldValue. If we get same record (this can happen as we
      // walk up the tree) we ignore the new record.

      if (records.length > 0) {
        var lastRecord = records[length - 1];
        var recordToReplaceLast = selectRecord(lastRecord, record);

        if (recordToReplaceLast) {
          records[length - 1] = recordToReplaceLast;
          return;
        }
      } else {
        scheduleCallback(this.observer);
      }

      records[length] = record;
    },
    addListeners: function addListeners() {
      this.addListeners_(this.target);
    },
    addListeners_: function addListeners_(node) {
      var options = this.options;
      if (options.attributes) node.addEventListener('DOMAttrModified', this, true);
      if (options.characterData) node.addEventListener('DOMCharacterDataModified', this, true);
      if (options.childList) node.addEventListener('DOMNodeInserted', this, true);
      if (options.childList || options.subtree) node.addEventListener('DOMNodeRemoved', this, true);
    },
    removeListeners: function removeListeners() {
      this.removeListeners_(this.target);
    },
    removeListeners_: function removeListeners_(node) {
      var options = this.options;
      if (options.attributes) node.removeEventListener('DOMAttrModified', this, true);
      if (options.characterData) node.removeEventListener('DOMCharacterDataModified', this, true);
      if (options.childList) node.removeEventListener('DOMNodeInserted', this, true);
      if (options.childList || options.subtree) node.removeEventListener('DOMNodeRemoved', this, true);
    },

    /**
     * Adds a transient observer on node. The transient observer gets removed
     * next time we deliver the change records.
     * @param {Node} node
     */
    addTransientObserver: function addTransientObserver(node) {
      // Don't add transient observers on the target itself. We already have all
      // the required listeners set up on the target.
      if (node === this.target) return;
      this.addListeners_(node);
      this.transientObservedNodes.push(node);
      var registrations = registrationsTable.get(node);
      if (!registrations) registrationsTable.set(node, registrations = []); // We know that registrations does not contain this because we already
      // checked if node === this.target.

      registrations.push(this);
    },
    removeTransientObservers: function removeTransientObservers() {
      var transientObservedNodes = this.transientObservedNodes;
      this.transientObservedNodes = [];
      transientObservedNodes.forEach(function (node) {
        // Transient observers are never added to the target.
        this.removeListeners_(node);
        var registrations = registrationsTable.get(node);

        for (var i = 0; i < registrations.length; i++) {
          if (registrations[i] === this) {
            registrations.splice(i, 1); // Each node can only have one registered observer associated with
            // this observer.

            break;
          }
        }
      }, this);
    },
    handleEvent: function handleEvent(e) {
      // Stop propagation since we are managing the propagation manually.
      // This means that other mutation events on the page will not work
      // correctly but that is by design.
      e.stopImmediatePropagation();

      switch (e.type) {
        case 'DOMAttrModified':
          // http://dom.spec.whatwg.org/#concept-mo-queue-attributes
          var name = e.attrName;
          var namespace = e.relatedNode.namespaceURI;
          var target = e.target; // 1.

          var record = new getRecord('attributes', target);
          record.attributeName = name;
          record.attributeNamespace = namespace; // 2.

          var oldValue = null;
          if (!(typeof MutationEvent !== 'undefined' && e.attrChange === MutationEvent.ADDITION)) oldValue = e.prevValue;
          forEachAncestorAndObserverEnqueueRecord(target, function (options) {
            // 3.1, 4.2
            if (!options.attributes) return; // 3.2, 4.3

            if (options.attributeFilter && options.attributeFilter.length && options.attributeFilter.indexOf(name) === -1 && options.attributeFilter.indexOf(namespace) === -1) {
              return;
            } // 3.3, 4.4


            if (options.attributeOldValue) return getRecordWithOldValue(oldValue); // 3.4, 4.5

            return record;
          });
          break;

        case 'DOMCharacterDataModified':
          // http://dom.spec.whatwg.org/#concept-mo-queue-characterdata
          var target = e.target; // 1.

          var record = getRecord('characterData', target); // 2.

          var oldValue = e.prevValue;
          forEachAncestorAndObserverEnqueueRecord(target, function (options) {
            // 3.1, 4.2
            if (!options.characterData) return; // 3.2, 4.3

            if (options.characterDataOldValue) return getRecordWithOldValue(oldValue); // 3.3, 4.4

            return record;
          });
          break;

        case 'DOMNodeRemoved':
          this.addTransientObserver(e.target);
        // Fall through.

        case 'DOMNodeInserted':
          // http://dom.spec.whatwg.org/#concept-mo-queue-childlist
          var target = e.relatedNode;
          var changedNode = e.target;
          var addedNodes, removedNodes;

          if (e.type === 'DOMNodeInserted') {
            addedNodes = [changedNode];
            removedNodes = [];
          } else {
            addedNodes = [];
            removedNodes = [changedNode];
          }

          var previousSibling = changedNode.previousSibling;
          var nextSibling = changedNode.nextSibling; // 1.

          var record = getRecord('childList', target);
          record.addedNodes = addedNodes;
          record.removedNodes = removedNodes;
          record.previousSibling = previousSibling;
          record.nextSibling = nextSibling;
          forEachAncestorAndObserverEnqueueRecord(target, function (options) {
            // 2.1, 3.2
            if (!options.childList) return; // 2.2, 3.3

            return record;
          });
      }

      clearRecords();
    }
  };

  if (!MutationObserver) {
    MutationObserver = JsMutationObserver;
  }

  var mutationObserver = MutationObserver;

  /**
   * 监听
   */
  /**
   * 函数
   * @param container 容器
   * @param callback 回调函数
   */
  function observe(container, callback) {
      const observer = new mutationObserver(callback);
      observer.observe(container, { childList: true, subtree: true });
  }

  /**
   * 查询
   */
  /**
   * 函数
   * @param container 容器
   * @return 广告元素
   */
  function query(container) {
      let iterator = document.evaluate('//*[text()="广告"]', container);
      let result = [];
      let node = iterator.iterateNext();
      while (node) {
          let temp = node;
          while (temp.parentNode !== container) {
              temp = temp.parentNode;
          }
          result.push(temp);
          node = iterator.iterateNext();
      }
      return result;
  }

  /**
   * 核心
   */
  /**
   * 函数
   */
  function core() {
      let container = document.querySelector('#content_left');
      if (container) {
          const clear = () => {
              let nodes = query(container);
              nodes.forEach(a => a.remove());
          };
          clear();
          observe(container, clear);
      }
  }

  /**
   * index
   */
  core();

})();