Obtener el código fuente HTML de la página actual de la extensión de Chrome

85

Tengo una extensión de Chrome. Necesito analizar desde la fuente HTML de la página actual. Encontré aquí todo tipo de soluciones con páginas de fondo y scripts de contenido, pero ninguna me ayudó. esto es lo que tengo hasta ahora:
manifest.json:

{
  "name": "Extension",
  "version": "1.0",
  "description": "Extension",
  "browser_action": {
    "default_icon": "bmarkred.ico",
    "popup": "Test.html"
  },
  "content_scripts": [
    {
      "matches": ["http://*/*"],
      "js": ["content.js"]
    }
  ],
  "background": {
    "page": "backgroundPage.html"
  },
  "permissions": [
    "cookies",
    "tabs",
    "http://*/*", 
    "https://*/*"
  ]
}

background.html:

<html>
<head>
<script type="text/javascript">
    try {
        chrome.tabs.getSelected(null, function (tab) {
            chrome.tabs.sendRequest(tab.id, {action: "getSource"}, function(source) {
                alert(source);
            });
        });
    }
    catch (ex) {
        alert(ex);
    }
</script>
</head>
</html>

content.js:

chrome.extension.onRequest.addListener(function(request, sender, callback) {
    if (request.action == "getSource") {
        callback(document.getElementsByTagName('html')[0].innerHTML);
    }
});

La alerta siempre alerta indefinida. incluso si cambio en el archivo content.js la función de devolución de llamada a:

callback('hello'); 

sigue siendo el mismo resultado. ¿Qué estoy haciendo mal? tal vez estoy haciendo esto de la manera incorrecta. lo que realmente necesito es esto. Cuando el usuario abre la ventana emergente de la extensión (y solo entonces), necesito HTML de la página actual para poder analizarla. ¿alguna sugerencia?

Sr. T.
fuente
Un problema es que el código en su página de fondo se ejecuta inmediatamente (antes de que se inyecten los scripts de contenido). Antes se ha hecho una pregunta muy similar / duplicada; Eche un vistazo a la respuesta en Abrir una nueva pestaña de Google Chrome y obtenga la fuente .
Rob W
Gracias por tu respuesta rob. Copié los segmentos de código en su enlace adjunto pero todavía no funciona. El problema es que mi extensión es una ventana emergente y necesito obtener el HTML solo cuando el usuario abre mi extensión. por ejemplo, si la pestaña actual es facebook.com, solo cuando abra mi extensión, recuperaré la fuente html en mi archivo js (no el script de contenido o la página de fondo).
Mr T.
Actualice su pregunta con su código actual. El código debe contener comentarios que resalten el problema.
Rob W

Respuestas:

155

Inyecte un script en la página de la que desea obtener la fuente y envíele un mensaje a la ventana emergente ...

manifest.json

{
  "name": "Get pages source",
  "version": "1.0",
  "manifest_version": 2,
  "description": "Get pages source from a popup",
  "browser_action": {
    "default_icon": "icon.png",
    "default_popup": "popup.html"
  },
  "permissions": ["tabs", "<all_urls>"]
}

popup.html

<!DOCTYPE html>
<html style=''>
<head>
<script src='popup.js'></script>
</head>
<body style="width:400px;">
<div id='message'>Injecting Script....</div>
</body>
</html>

popup.js

chrome.runtime.onMessage.addListener(function(request, sender) {
  if (request.action == "getSource") {
    message.innerText = request.source;
  }
});

function onWindowLoad() {

  var message = document.querySelector('#message');

  chrome.tabs.executeScript(null, {
    file: "getPagesSource.js"
  }, function() {
    // If you try and inject into an extensions page or the webstore/NTP you'll get an error
    if (chrome.runtime.lastError) {
      message.innerText = 'There was an error injecting script : \n' + chrome.runtime.lastError.message;
    }
  });

}

window.onload = onWindowLoad;

getPagesSource.js

// @author Rob W <http://stackoverflow.com/users/938089/rob-w>
// Demo: var serialized_html = DOMtoString(document);

function DOMtoString(document_root) {
    var html = '',
        node = document_root.firstChild;
    while (node) {
        switch (node.nodeType) {
        case Node.ELEMENT_NODE:
            html += node.outerHTML;
            break;
        case Node.TEXT_NODE:
            html += node.nodeValue;
            break;
        case Node.CDATA_SECTION_NODE:
            html += '<![CDATA[' + node.nodeValue + ']]>';
            break;
        case Node.COMMENT_NODE:
            html += '<!--' + node.nodeValue + '-->';
            break;
        case Node.DOCUMENT_TYPE_NODE:
            // (X)HTML documents are identified by public identifiers
            html += "<!DOCTYPE " + node.name + (node.publicId ? ' PUBLIC "' + node.publicId + '"' : '') + (!node.publicId && node.systemId ? ' SYSTEM' : '') + (node.systemId ? ' "' + node.systemId + '"' : '') + '>\n';
            break;
        }
        node = node.nextSibling;
    }
    return html;
}

chrome.runtime.sendMessage({
    action: "getSource",
    source: DOMtoString(document)
});
PAEz
fuente
@Gil Tankus Lo siento por mi primera publicación, no presté suficiente atención a los comentarios (nuevamente) y terminé regurgitando lo que dijo Rob W. La nueva publicación debería tener lo que querías.
PAEz
Gracias, su respuesta fue realmente útil, mi problema es que el onMessage ocurre de forma asincrónica. en mi ventana emergente, tengo todo tipo de otras cosas que se relacionan con el código fuente HTML. ¿Cómo puedo guardar la fuente en una var global y solo luego continuar con la función de carga de página?
Mr T.
No creo que puedas. O tendrá que ponerlo en el código de devolución de llamada o en una función y llamarlo en la devolución de llamada ... si solo JS tuviera un gotocomando, ¿sí? ; P
PAEz
19
¿Por qué no algo como document.documentElement.outerHTML en lugar de la función DOMtoString?
djfm
@djfm Eso estaría bien casi todo el tiempo. Es solo que, por lo que pude decir, la función de Rob W es más completa ... devuelve el tipo de documento, por ejemplo, que su solución no lo hace, la suya solo obtiene la parte html.
PAEz
0

Aquí está mi solución:

chrome.runtime.onMessage.addListener(function(request, sender) {
        if (request.action == "getSource") {
            this.pageSource = request.source;
            var title = this.pageSource.match(/<title[^>]*>([^<]+)<\/title>/)[1];
            alert(title)
        }
    });

    chrome.tabs.query({ active: true, currentWindow: true }, tabs => {
        chrome.tabs.executeScript(
            tabs[0].id,
            { code: 'var s = document.documentElement.outerHTML; chrome.runtime.sendMessage({action: "getSource", source: s});' }
        );
    });
Dejan S
fuente