[英]Stop execution of Javascript function (client side) or tweak it
我想停止从站点执行一行,以便浏览器读取整个页面,除了那一行。 或者浏览器可能会简单地跳过该 javascript 函数的执行。
或者
有没有办法我可以以某种方式调整javascript,以便javascript中的随机数生成函数不生成随机数,但我想要的数字...
我无权访问托管脚本的站点,因此所有这些都需要在客户端完成。
Firefox 当前支持beforescriptexecute事件(从第 4 版开始,于 2011 年 3 月 22 日发布) ‡ 。
通过该事件和// @run-at document-start
指令,Firefox 和 Greasemonkey 现在似乎可以很好地拦截特定的<script>
标签。
这对于 Chrome+Tampermonkey 仍然是不可能的。 对于 Firefox+Greasemonkey 以外的任何东西,您都需要使用下面其他答案中所示的技术来编写完整的浏览器扩展。
checkForBadJavascripts
函数对此进行了封装。 例如,假设页面有一个<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 中的内联文档。
要查看完整脚本中的演示,请首先访问jsBin 上的此页面。 您将看到 3 行文本,其中两行是 JS 添加的。
现在, 安装此脚本(查看源代码;它也在下面。)并重新访问该页面。 你会看到 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);
}
答案取决于未提供的详细信息(最好是确切的页面和代码行),但一般情况下您可以这样做:
如果有问题的JS 代码没有立即触发(在DOMContentLoaded
之后触发),那么您可以使用 Greasemonkey 替换有问题的代码。 例如:
var scriptNode = document.createElement ("script"); scriptNode.textContent = "Your JS code here"; document.head.appendChild (scriptNode);
完毕。
如果JS 代码立即触发,那么它会变得更加复杂。
首先,获取脚本的副本并对其进行所需的更改。 将其保存在本地。
有问题的脚本是在文件中还是在主页 HTML 中( <script src="Some File>
与<script>Mess O' Code</script>
)?
如果脚本在文件中,请安装Adblock Plus并使用它来阻止加载该脚本。 然后使用 Greasemonkey 将修改后的代码添加到页面。 例如:
var scriptNode = document.createElement ("script"); scriptNode.setAttribute ("src", "Point to your modified JS file here."); document.head.appendChild (scriptNode);
如果脚本位于主 HTML 页面中,则安装NoScript (最佳)或YesScript并使用它来阻止来自该站点的 JavaScript。
这意味着您随后需要使用 Greasemonkey 替换该站点中您想要运行的所有脚本。
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 加载到 Stack Overflow 上的<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 - 在页面加载<head>
内的任何内容之前,您需要@run-at document-start
附加它。 (如果使用 Tampermonkey / Chrome,您可能需要启用实验性即时脚本注入以可靠地实现这一点 - 转到 Tampermonkey 设置,配置模式:高级,滚动到底部,将实验性注入模式设置为即时。)
如果您正在为其他人编写用户脚本,任何您正在使用这种技术,请确保包含即时脚本注入的说明,因为在 Chrome 上默认情况下注入不是即时的。
请注意,观察者是使用附加的
.observe(document.documentElement, { childList: true, subtree: true });
这将观察者附加到<html>
元素,使用childList: true
添加和删除的直接子childList: true
,并使用subtree: true
其后代中任何位置添加和删除的节点。 这种递归侦听器很有用,但它在大型动态页面上的计算成本也很高,因此请确保在达到目的后将其删除。
在一个巨大的页面上,在每个突变上调用querySelector
可能代价高昂,因此您可能希望遍历mutations
(观察者回调的第一个参数)和突变的addedNodes
:
<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>
您还可以通过在观察者回调中分配给它们的textContent
来调整内联脚本。 以下代码段显示了如何将随机数生成器函数更改为始终返回 10,而不是 1-6:
<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>
方法 1 是您在为他人编写用户脚本时可以使用的技术。 但是,如果用户脚本仅供您自己使用,则有一种更简单的方法可以在某些情况下使用。 请参阅Chrome Dev Tools - Modify javascript and reload问题的答案:通过转到 Chrome Devtools 中的 Sources -> Overrides 选项卡,并启用本地覆盖,您可以告诉浏览器加载.js
的本地副本而不是下载网站的版本。 然后您可以根据需要编辑本地副本,它将运行而不是内置脚本。 调整较大的JavaScript文件时,这是非常有用的-它比MutationObserver方法更易于管理。
但是,有一些缺点:
<script>// code here</script>
标记,您必须下载页面的本地副本。 (因此,如果页面通过 HTML 响应提供动态内容,则您必须重新保存并重新调整.html
以使用新内容,否则您必须返回 MutationObserver 方法.)您可以使用所谓的书签。
构建你想在其他站点上运行的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
时your.js
使用 TamperMonkey? 所有你需要添加下面的// @grant
在TamperMonkey标题是// @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==
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.