【问题标题】:Changing Javascript on an HTML page out of my control [duplicate]在我无法控制的 HTML 页面上更改 Javascript [重复]
【发布时间】:2015-10-09 07:01:56
【问题描述】:

我正在使用我无法控制的 HTML 页面。它在内联 <script> 标记中定义了一个 Javascript 函数,并在 <body onload="..."> 中调用它:

<html>
...
<body onload="init()">
<script type="text/javascript" language="javascript">
    function init() {
        ...
    }
</script>
...

如何在调用之前更改该函数?我尝试使用 Greasemonkey 修改脚本或在其后插入另一个脚本以覆盖该函数,但似乎没有任何效果。

【问题讨论】:

  • 如果你仍然可以修改上面的 JavaScript,这个 HTML 页面有多少是你无法控制的?
  • @Hawken:Greasemonkey 是一个浏览器插件,用于在呈现之前重写传入的 HTML

标签: javascript greasemonkey


【解决方案1】:

Greasemonkey 现在通常可以通过利用the beforescriptexecute event@run-at document-start 来做这种事情。请注意,似乎只有 Firefox 支持该事件,因此这不适用于 Chrome。有关更繁琐的方法,请参阅 herehere

要在调用 init() 函数之前对其进行更改,请利用下面定义的 checkForBadJavascripts() 函数。

你可以这样称呼它:

//--- New "init" function to replace the bad one.
function init () {
    //... Do what you want here...
}

checkForBadJavascripts ( [
    [false, /function\s+init(/, function () {addJS_Node (init);} ]
] );

其中function\s+init( 必须是您定位的&lt;script&gt; 标记的唯一位置。 (请注意,addJS_Node() 也在下面定义。)


例如,访问this page at jsBin。你会看到 3 行文本,其中两行是 JS 添加的。

现在,安装以下脚本并重新访问该页面。您会看到 GM 脚本删除了一个错误的 &lt;script&gt; 标签,并用我们的“好”JS 替换了另一个。

// ==UserScript==
// @name        _Replace evil Javascript
// @include     http://output.jsbin.com/tezoni*
// @run-at      document-start
// @grant       none
// ==/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);
}

【讨论】:

  • 这段代码对我不起作用。它也非常长和复杂。更不用说它在自身内部重新定义了checkForBadJavascripts 函数。
  • @Rebs,(1) 如果需要,请打开一个带有正确 问题描述的问题。通过使用 Firefox+Greasemonkey 按照帖子中的说明,您可以看到该代码仍然有效。 ...我刚刚更新了目标页面,但旧页面只是被 jsbin 损坏了一点。至于你的最后两点,你是非常错误的。该代码的作用很简单,这是一种有效且有用的 JS 技术。请删除您错误的反对票。
【解决方案2】:

以下 Greasemonkey 用户脚本(基于 this source)终于为我工作了。它通过在现有script 标记之后的新script 标记中定义另一个具有相同名称的函数来覆盖现有函数。不需要@run-atbeforescriptexecute

var firstScript = document.body.getElementsByTagName('script')[0];
var newScript = document.createElement('script');
var scriptArray = new Array();
scriptArray.push('function init() {');
scriptArray.push('    ...');
scriptArray.push('}');
newScript.innerHTML = scriptArray.join('\n');
scriptArray.length = 0; // free this memory
firstScript.parentNode.insertBefore(newScript, firstScript.nextSibling);

我之前没有太多使用 Greasemonkey 甚至 Javascript 的经验,所以我发现 Firefox Web Developer 工具必不可少,具体来说:

  • 错误控制台可捕获您一定会犯的许多小错误。和
  • 检查工具以查看生成的 HTML(因为常规查看源代码不会显示该内容!)。

【讨论】:

  • 如果这行得通,我相信这纯粹是运气。它设置了一个“竞争条件”,这意味着虽然它可能在某些页面上工作,但有时它不应该在其他页面上工作,具体取决于它们的组成。
猜你喜欢
  • 2021-04-18
  • 2012-10-25
  • 1970-01-01
  • 1970-01-01
  • 2018-01-22
  • 2019-08-22
  • 1970-01-01
  • 1970-01-01
  • 2020-11-29
相关资源
最近更新 更多