停止执行Javascript函数(客户端)或调整它

时间:2010-10-19 19:38:29

标签: javascript greasemonkey

我想停止从站点执行一行,以便除了该行之外,浏览器会读取整个页面。或者浏览器可能只是跳过执行该javascript函数。

OR

有没有办法我可以以某种方式调整javascript,以便javascript中的随机数生成函数不生成随机数,但我想要的数字...

我无权访问托管脚本的网站,因此所有这些都需要在客户端完成。

5 个答案:

答案 0 :(得分:36)

Firefox目前支持the beforescriptexecute event(截至Version 4, released on March 22, 2011

通过该事件和the // @run-at document-start directive,Firefox和Greasemonkey现在似乎可以很好地拦截特定的<script>标签。

Chrome + Tampermonkey 仍然无法做到这一点。除了Firefox + Greasemonkey之外,您还需要使用下面其他答案中所示的技术来编写完整的浏览器扩展。

The checkForBadJavascripts function封装了这个。例如,假设页面具有<script>标记,如下所示:

<script>
    alert ("Sorry, Sucka!  You've got no money left.");
</script>

你可以这样使用checkForBadJavascripts

checkForBadJavascripts ( [
    [   false, 
        /Sorry, Sucka/, 
        function () {
            addJS_Node ('alert ("Hooray, you\'re a millionaire.");');
        } 
    ]
] );

获得更好的消息。 (^_^)
有关详细信息,请参阅 checkForBadJavascripts 中的内联文档。


要在完整脚本中查看演示,请先访问this page at jsBin。您将看到3行文本,其中两行由JS添加。

现在,install this scriptView source;它也在下面。)并重新访问该页面。您将看到GM脚本删除了一个坏标签,并用我们的“好”JS替换了另一个。


请注意,只有Firefox支持beforescriptexecute事件。它已从HTML5规范中删除,未指定等效功能。



完整的GM脚本示例(与GitHub和jsBin上的相同):

鉴于此HTML:

<body onload="init()">
<script type="text/javascript" src="http://jsbin.com/evilExternalJS/js"></script>
<script type="text/javascript" language="javascript">
    function init () {
        var newParagraph            = document.createElement ('p');
        newParagraph.textContent    = "I was added by the old, evil init() function!";
        document.body.appendChild (newParagraph);
    }
</script>
<p>I'm some initial text.</p>
</body>


使用这个Greasemonkey脚本:

// ==UserScript==
// @name        _Replace evil Javascript
// @include     http://jsbin.com/ogudon*
// @run-at      document-start
// ==/UserScript==

/****** New "init" function that we will use
    instead of the old, bad "init" function.
*/
function init () {
    var newParagraph            = document.createElement ('p');
    newParagraph.textContent    = "I was added by the new, good init() function!";
    document.body.appendChild (newParagraph);
}

/*--- Check for bad scripts to intercept and specify any actions to take.
*/
checkForBadJavascripts ( [
    [false, /old, evil init()/, function () {addJS_Node (init);} ],
    [true,  /evilExternalJS/i,  null ]
] );

function checkForBadJavascripts (controlArray) {
    /*--- Note that this is a self-initializing function.  The controlArray
        parameter is only active for the FIRST call.  After that, it is an
        event listener.

        The control array row is  defines like so:
        [bSearchSrcAttr, identifyingRegex, callbackFunction]
        Where:
            bSearchSrcAttr      True to search the SRC attribute of a script tag
                                false to search the TEXT content of a script tag.
            identifyingRegex    A valid regular expression that should be unique
                                to that particular script tag.
            callbackFunction    An optional function to execute when the script is
                                found.  Use null if not needed.
    */
    if ( ! controlArray.length) return null;

    checkForBadJavascripts      = function (zEvent) {

        for (var J = controlArray.length - 1;  J >= 0;  --J) {
            var bSearchSrcAttr      = controlArray[J][0];
            var identifyingRegex    = controlArray[J][1];

            if (bSearchSrcAttr) {
                if (identifyingRegex.test (zEvent.target.src) ) {
                    stopBadJavascript (J);
                    return false;
                }
            }
            else {
                if (identifyingRegex.test (zEvent.target.textContent) ) {
                    stopBadJavascript (J);
                    return false;
                }
            }
        }

        function stopBadJavascript (controlIndex) {
            zEvent.stopPropagation ();
            zEvent.preventDefault ();

            var callbackFunction    = controlArray[J][2];
            if (typeof callbackFunction == "function")
                callbackFunction ();

            //--- Remove the node just to clear clutter from Firebug inspection.
            zEvent.target.parentNode.removeChild (zEvent.target);

            //--- Script is intercepted, remove it from the list.
            controlArray.splice (J, 1);
            if ( ! controlArray.length) {
                //--- All done, remove the listener.
                window.removeEventListener (
                    'beforescriptexecute', checkForBadJavascripts, true
                );
            }
        }
    }

    /*--- Use the "beforescriptexecute" event to monitor scipts as they are loaded.
        See https://developer.mozilla.org/en/DOM/element.onbeforescriptexecute
        Note that it does not work on acripts that are dynamically created.
    */
    window.addEventListener ('beforescriptexecute', checkForBadJavascripts, true);

    return checkForBadJavascripts;
}

function addJS_Node (text, s_URL, funcToRun) {
    var D                                   = document;
    var scriptNode                          = D.createElement ('script');
    scriptNode.type                         = "text/javascript";
    if (text)       scriptNode.textContent  = text;
    if (s_URL)      scriptNode.src          = s_URL;
    if (funcToRun)  scriptNode.textContent  = '(' + funcToRun.toString() + ')()';

    var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
    //--- Don't error check here. if DOM not available, should throw error.
    targ.appendChild (scriptNode);
}

答案 1 :(得分:7)

答案取决于未提供的详细信息(确切的页面和代码行最好),但一般来说,这是你如何做的:

  1. 如果违规的 JS代码没有立即启动(在DOMContentLoaded之后触发),那么您可以使用Greasemonkey替换有问题的代码。 EG:

    var scriptNode          = document.createElement ("script");
    scriptNode.textContent  = "Your JS code here";
    document.head.appendChild (scriptNode);
    

    完成。

  2. 如果 JS代码立即触发,则会变得更复杂 首先,获取脚本的副本并对其进行所需的更改。在本地保存。

  3. 违规脚本是在文件中还是主页面HTML(<script src="Some File><script>Mess O' Code</script>)?

  4. 如果脚本在文件中,请安装Adblock Plus并使用它来阻止加载该脚本。然后使用Greasemonkey将修改后的代码添加到页面中。 EG:

    var scriptNode          = document.createElement ("script");
    scriptNode.setAttribute ("src", "Point to your modified JS file here.");
    document.head.appendChild (scriptNode);
    
  5. 如果脚本位于主HTML页面中,请安装NoScript(最佳)或YesScript并使用它来阻止来自该网站的JavaScript。
    这意味着您将需要使用Greasemonkey替换您想要运行的所有脚本。

答案 2 :(得分:0)

beforescriptexecute在Firefox中不再起作用,在Chrome中也不再起作用。幸运的是,还有一种使用MutationObserver的替代方法,它得到了广泛的支持。一般的想法是在页面加载开始时添加MutationObserver,每当将新节点添加到DOM时,该方法都会运行回调。在回调内部,检查您要更改或删除的<script>标签是否存在。如果存在,则可以对其进行篡改(例如更改其textContent或将其src指向其他位置)。只有在回调结束后 才会运行新添加的script标签,因此这是一种拦截和更改页面上Javascript的有效方法。这是一个实时片段示例:

<script>
  // This is the userscript code, which runs at the beginning of pageload
  // Say we wanted to prevent the loading of the jQuery script tag below:
  new MutationObserver((_, observer) => {
    const jqueryScriptTag = document.querySelector('script[src*="jquery"]');
    if (jqueryScriptTag) {
      console.log('Found jQuery script tag; now removing it!');
      jqueryScriptTag.remove();
      // We've done what we needed to do, no need for the MutationObserver anymore:
      observer.disconnect();
    }
  })
    .observe(document.documentElement, { childList: true, subtree: true });
</script>
<div>Example content</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<script>
  console.log('After jQuery script tag. If done right, $ should be undefined:');
  console.log(typeof $);
</script>

下面是一个示例用户脚本,该脚本阻止jQuery在堆栈溢出的<head>中加载:

// ==UserScript==
// @name             Example jQuery removal
// @include          https://stackoverflow.com*
// @run-at           document-start
// @grant            none
// ==/UserScript==

if (document.head) {
  throw new Error('Head already exists - make sure to enable instant script injection');
}
new MutationObserver((_, observer) => {
  const jqueryScriptTag = document.querySelector('script[src*="jquery"]');
  if (jqueryScriptTag) {
    jqueryScriptTag.remove();
    observer.disconnect();
  }
})
  .observe(document.documentElement, { childList: true, subtree: true });

如果安装此工具,则会看到jQuery的加载失败,从而导致Stack Overflow的JS生成许多错误。

请确保尽快附加MutationObserver-在页面加载@run-at document-start中的任何内容之前,需要<head>附加它。 (如果使用Tampermonkey / Chrome,则可能需要启用实验性即时脚本注入才能可靠地实现此目的-转到Tampermonkey设置,配置模式:“高级”,滚动到底部,将“实验性注入模式”设置为“即时”。)

如果您正在为其他用户编写用户脚本,则使用此技术的任何人都请确保包括即时脚本注入的说明,因为默认情况下,注入不是即时在Chrome上即时进行的。

请注意,观察者是使用

附加的
.observe(document.documentElement, { childList: true, subtree: true });

这会将观察者附加到<html>元素,使用childList: true监视添加和删除的直接子节点,并使用{监视其后代中任何位置的添加和删除的节点 {1}}。这样的递归侦听器很有用,但在大型动态页面上在计算上也很昂贵,因此请确保在达到其目的后将其删除。

在一个很大的页面上,对每个突变调用subtree: true可能会很昂贵,因此您可能要遍历querySelector(观察者回调的第一个参数)和突变的{{1 }}:

mutations

您还可以通过在观察者回调中将其分配给addedNodes来调整内联脚本。以下代码段显示了如何更改随机数生成器函数以始终返回10而不是1-6:

<script>
  // This is the userscript code, which runs at the beginning of pageload
  // Say we wanted to prevent the loading of the jQuery script tag below:
  new MutationObserver((mutations, observer) => {
    for (const mutation of mutations) {
      for (const addedNode of mutation.addedNodes) {
        if (addedNode.nodeType === 1 && addedNode.matches('script[src*="jquery"]')) {
          console.log('Found jQuery script tag; now removing it!');
          addedNode.remove();
          // We've done what we needed to do, no need for the MutationObserver anymore:
          observer.disconnect();
          return;
        }
      }
    }
  })
    .observe(document.documentElement, { childList: true, subtree: true });
</script>
<div>Example content</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<script>
  console.log('After jQuery script tag. If done right, $ should be undefined:');
  console.log(typeof $);
</script>


以上是编写其他用户脚本时可以使用的技术。但是,如果用户脚本仅用于您自己,那么有一种更简单的方法可以在某些情况下使用。请参见问题Chrome Dev Tools - Modify javascript and reload的以下答案:通过转到Chrome Devtools中的“源”->“替代”标签,并启用本地替代,您可以告诉浏览器加载textContent的本地副本,而不是下载网站的版本。然后,您可以根据需要编辑本地副本,它将代替内置脚本运行。在调整大型Javascript文件时,此功能特别有用-它比MutationObserver方法更易管理。

但是,有一些缺点:

  • 要修改内嵌<script> // This is the userscript code, which runs at the beginning of pageload new MutationObserver((mutations, observer) => { for (const mutation of mutations) { for (const addedNode of mutation.addedNodes) { if (addedNode.textContent.includes('const randomNum')) { addedNode.textContent = addedNode.textContent.replace( /const randomNum.*/, 'const randomNum = 10;' ); observer.disconnect(); return; } } } }) .observe(document.documentElement, { childList: true, subtree: true }); </script> <button>Roll Die</button> <div>Results: <span></span></div> <script> const [button, span] = ['button', 'span'].map(tag => document.querySelector(tag)); button.onclick = () => { const randomNum = Math.ceil(Math.random() * 6); span.textContent = randomNum; }; </script>标签,您必须下载页面的本地副本。 (因此,如果页面通过HTML响应提供动态内容,则您必须重新保存和重新调整.js才能覆盖使用新内容的覆盖,或者,您必须返回到MutationObserver方法。)
  • 这是开发人员开发人员可以理解的技术(经过一些试验),但是它并不那么友好。也许这不是您想要吸引休闲的用户脚本使用者的事情。

答案 3 :(得分:-1)

您可以使用所谓的书签。

构建您要在其他网站上运行的js文件:your.js

使用以下代码制作HTML页面:

<html>
<body>
  <a href="javascript:(function(){var s=document.createElement('SCRIPT');s.src='/url/to/your.js?'+(Math.random());document.getElementsByTagName('head')[0].appendChild(s);})()">
    Drag'n Drop this to your bookmarks
  </a>
</body>
</html>

/url/to/your.js替换为js文件的路径。

在浏览器中加载该小页面,然后将链接拖放到书签栏。

转到要破解的网站,然后单击刚刚创建的书签。
这将在页面中加载your.js并运行代码。

注意?'+(Math.random())部分是为了避免js被缓存,这不是强制性的,但在开发your.js

时很有帮助

答案 4 :(得分:-1)

使用TamperMonkey?您需要在TamperMonkey标头中的// @grant下方添加// @require http://urlofyoursite.com/myfile.js。例如,这是我的TamperMonkey事物的顶部:

// ==UserScript==
// @name         Project
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        https://docs.google.com/presentation/*
// @grant        none
// @require http://cdnjs.cloudflare.com/ajax/libs/annyang/2.1.0/annyang.min.js
// ==/UserScript==