Detener la ejecución de la función Javascript (lado del cliente) o modificarla
Quiero detener la ejecución de una sola línea de un sitio, para que el navegador lea toda la página excepto esa única línea. O el navegador puede simplemente omitir la ejecución de esa función de JavaScript.
O
¿Hay alguna manera de modificar JavaScript de alguna manera para que la función de generación de números aleatorios en JavaScript no genere números aleatorios, sino los números que quiero...
No tengo acceso al sitio en el que está alojado el script, por lo que todo esto debe hacerse desde el lado del cliente.
Firefox actualmente admite el evento beforescriptexecute (a partir de la versión 4, lanzada el 22 de marzo de 2011 ) ‡ .
Con ese evento y la // @run-at document-start
directiva , Firefox y Greasemonkey ahora parecen hacer un buen trabajo interceptando <script>
etiquetas específicas.
Esto todavía no es posible para Chrome+Tampermonkey . Para cualquier cosa que no sea Firefox+Greasemonkey, necesitarás usar técnicas como se muestran en las otras respuestas, a continuación, para escribir una extensión de navegador completa.
La checkForBadJavascripts
función resume esto. Por ejemplo, supongamos que la página tuviera una <script>
etiqueta como esta:
<script>
alert ("Sorry, Sucka! You've got no money left.");
</script>
Podrías usar checkForBadJavascripts
así:
checkForBadJavascripts ( [
[ false,
/Sorry, Sucka/,
function () {
addJS_Node ('alert ("Hooray, you\'re a millionaire.");');
}
]
] );
para recibir un mensaje mucho más agradable. (^_^)
Consulte la documentación en línea, en checkForBadJavascripts , para obtener más información.
Para ver una demostración en un script completo, primero visite esta página en jsBin . Verás 3 líneas de texto, dos de ellas agregadas por JS.
Ahora, instale este script ( Ver código fuente ; también se encuentra a continuación) y vuelva a visitar la página. Verá que el script GM eliminó una etiqueta incorrecta y reemplazó otra con nuestro JS "bueno".
‡ Tenga en cuenta que solo Firefox admite el beforescriptexecute
evento. Y se eliminó de la especificación HTML5 sin especificar una capacidad equivalente.
Ejemplo completo de script GM (el mismo que el de GitHub y jsBin):
Dado este 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>
Utilice este script de 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);
}
Método 1: usar MutationObserver
beforescriptexecute
Ya no funciona en Firefox, ni tampoco en Chrome. Afortunadamente, existe una alternativa, usar MutationObserver
, que cuenta con un soporte bastante amplio. La idea general es agregar un MutationObserver al comienzo de la carga de la página, que ejecutará una devolución de llamada cada vez que se agregue un nuevo nodo al DOM. Dentro de la devolución de llamada, verifique la existencia de la <script>
etiqueta que desea modificar o eliminar. Si existe, puede alterarlo (como cambiarlo textContent
o tener su src
punto en otro lugar). Solo después de que finalice la devolución de llamada se ejecutará la etiqueta de script recién agregada, por lo que esta es una forma efectiva de interceptar y cambiar Javascript en una página. Aquí hay un ejemplo de fragmento en vivo:
Mostrar fragmento de código
Aquí hay un script de usuario de ejemplo que bloquea la carga de jQuery aquí <head>
en Stack Overflow:
// ==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 });
Si instala esto, verá que la carga de jQuery falla, lo que genera muchos errores generados por el JS de Stack Overflow.
Asegúrese de adjuntar el MutationObserver lo antes posible; debe @run-at document-start
adjuntarlo antes de que la página cargue algo dentro del archivo <head>
. (Si usa Tampermonkey/Chrome, es posible que necesite habilitar la inyección de script instantánea experimental para lograr esto de manera confiable; vaya a Configuración de Tampermonkey, Modo de configuración: Avanzado, desplácese hasta la parte inferior, configure el Modo de inyección experimental en Instantáneo).
Si está escribiendo scripts de usuario para otras personas o está utilizando esta técnica, asegúrese de incluir instrucciones para la inyección instantánea de scripts, ya que la inyección no es instantánea de forma predeterminada en Chrome.
Tenga en cuenta que el observador se adjunta utilizando
.observe(document.documentElement, { childList: true, subtree: true });
Esto vincula al observador al <html>
elemento, vigila si hay hijos inmediatos agregados y eliminados con childList: true
y vigila si hay nodos agregados y eliminados en cualquier lugar dentro de sus descendientes con subtree: true
. Un oyente recursivo de este tipo es útil, pero también es costoso desde el punto de vista computacional en páginas dinámicas grandes, así que asegúrese de eliminarlo una vez que haya logrado su propósito.
En una página enorme, invocar querySelector
cada mutación podría ser costoso, por lo que es posible que desees iterar a través de mutations
(el primer parámetro de la devolución de llamada del observador) y las mutaciones addedNodes
en su lugar:
Mostrar fragmento de código
También puede modificar los scripts en línea asignándolos textContent
dentro de la devolución de llamada del observador. El siguiente fragmento muestra cómo se puede cambiar una función de generación de números aleatorios para que siempre devuelva 10, en lugar de 1-6:
Mostrar fragmento de código
Método 2: usar anulaciones locales de DevTools
El método 1 es la técnica que puede utilizar al escribir scripts de usuario para otros . Pero si el script de usuario es solo para usted , existe un método más sencillo que puede funcionar en algunas situaciones. Vea esta respuesta a la pregunta Herramientas de desarrollo de Chrome: modifique JavaScript y vuelva a cargar : al ir a la pestaña Fuentes -> Anulaciones en Chrome Devtools y habilitar las anulaciones locales, puede indicarle al navegador que cargue una copia local de un .js
en lugar de descargar el sitio. versión. Luego puede editar la copia local como desee y se ejecutará en lugar del script integrado. Esto es especialmente útil cuando se modifican archivos Javascript grandes: es mucho más manejable que el enfoque MutationObserver.
Pero hay algunas desventajas:
- Para modificar
<script>// code here</script>
etiquetas en línea, deberá descargar una copia local de la página. (Entonces, si la página ofrece contenido dinámico a través de la respuesta HTML, tendrá que volver a guardar y modificar las.html
anulaciones para usar el nuevo contenido, o tendrá que volver al método MutationObserver). - Esta es una técnica que los desarrolladores pueden entender (después de experimentar un poco), pero no es tan fácil de usar. Puede que no sea el tipo de cosas por las que le gustaría guiar a un consumidor casual de scripts de usuario.
La respuesta depende de los detalles que no se proporcionaron (la página y la línea de código exactas serían las mejores), pero así es como se hace en general:
Si el código JS infractor no se activa de inmediato (se activa después
DOMContentLoaded
), puede usar Greasemonkey para reemplazar el código infractor. P.EJ:var scriptNode = document.createElement ("script"); scriptNode.textContent = "Your JS code here"; document.head.appendChild (scriptNode);
Hecho.
Si el código JS se activa inmediatamente , entonces se vuelve más complicado.
Primero, tome una copia del script y realice los cambios deseados. Guarde esto localmente.¿El script infractor está en un archivo o en la página principal HTML (
<script src="Some File>
versus<script>Mess O' Code</script>
)?Si el script está en un archivo, instale Adblock Plus y utilícelo para bloquear la carga de ese script. Luego use Greasemonkey para agregar su código modificado a la página. P.EJ:
var scriptNode = document.createElement ("script"); scriptNode.setAttribute ("src", "Point to your modified JS file here."); document.head.appendChild (scriptNode);
Si el script está en la página HTML principal, instale NoScript (mejor) o YesScript y utilícelo para bloquear JavaScript de ese sitio.
Esto significa que necesitarás usar Greasemonkey para reemplazar todos los scripts de ese sitio que quieras ejecutar.