web-dev-qa-db-fra.com

Chrome Extension - Obtenir le contenu du DOM

J'essaie d'accéder au contenu du domaine ActiveTab à partir de ma fenêtre contextuelle. Voici mon manifeste:

{
  "manifest_version": 2,

  "name": "Test",
  "description": "Test script",
  "version": "0.1",

  "permissions": [
    "activeTab",
    "https://api.domain.com/"
  ],

  "background": {
    "scripts": ["background.js"],
    "persistent": false
  },
  "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",

  "browser_action": {
    "default_icon": "icon.png",
    "default_title": "Chrome Extension test",
    "default_popup": "index.html"
  }
}

Je ne comprends vraiment pas si les scripts en arrière-plan (pages d'événement avec persistance: false) ou les scripts de contenu sont la solution. J'ai lu toute la documentation et d'autres SO articles et cela n'a toujours aucun sens pour moi.

Quelqu'un peut-il expliquer pourquoi je pourrais utiliser l'un sur l'autre.

Voici le fichier background.js que j'ai essayé:

chrome.extension.onMessage.addListener(
  function(request, sender, sendResponse) {
    // LOG THE CONTENTS HERE
    console.log(request.content);
  }
);

Et je suis en train de l'exécuter depuis la console popup:

chrome.tabs.getSelected(null, function(tab) {
  chrome.tabs.sendMessage(tab.id, { }, function(response) {
    console.log(response);
  });
});

Je suis en train:

Port: Could not establish connection. Receiving end does not exist. 

PDATE:

{
  "manifest_version": 2,

  "name": "test",
  "description": "test",
  "version": "0.1",

  "permissions": [
    "tabs",
    "activeTab",
    "https://api.domain.com/"
  ],

  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content.js"]
    }
  ],

  "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",

  "browser_action": {
    "default_icon": "icon.png",
    "default_title": "Test",
    "default_popup": "index.html"
  }
}

content.js

chrome.extension.onMessage.addListener(
  function(request, sender, sendResponse) {
    if (request.text && (request.text == "getDOM")) {
      sendResponse({ dom: document.body.innertHTML });
    }
  }
);

popup.html

chrome.tabs.getSelected(null, function(tab) {
  chrome.tabs.sendMessage(tab.id, { action: "getDOM" }, function(response) {
    console.log(response);
  });
});

Quand je le lance, j'obtiens toujours la même erreur:

undefined
Port: Could not establish connection. Receiving end does not exist. lastError:30
undefined
92
brandonhilkert

Les termes "page d'arrière-plan", "popup", "script de contenu" vous déroutent encore; Je suggère fortement de jeter un œil plus en profondeur sur la documentation de Google Chrome extensions.

Concernant votre question si les scripts de contenu ou les pages d’arrière-plan sont la voie à suivre:

Scripts de contenu : définitivement
Les scripts de contenu sont le seul composant d’une extension ayant accès au DOM de la page Web.

Page d'arrière-plan/Popup : Peut-être (probablement au maximum 1 des deux)
Le script de contenu devra peut-être transmettre le contenu du DOM à une page d’arrière-plan ou à la fenêtre contextuelle pour un traitement ultérieur.


Permettez-moi de répéter que je recommande vivement une étude plus minutieuse de la documentation disponible!
Cela dit, voici un exemple d'extension qui récupère le contenu du DOM sur les pages StackOverflow et l'envoie à la page d'arrière-plan, qui l'imprime à son tour dans la console:

background.js:

// Regex-pattern to check URLs against. 
// It matches URLs like: http[s]://[...]stackoverflow.com[...]
var urlRegex = /^https?:\/\/(?:[^./?#]+\.)?stackoverflow\.com/;

// A function to use as callback
function doStuffWithDom(domContent) {
    console.log('I received the following DOM content:\n' + domContent);
}

// When the browser-action button is clicked...
chrome.browserAction.onClicked.addListener(function (tab) {
    // ...check the URL of the active tab against our pattern and...
    if (urlRegex.test(tab.url)) {
        // ...if it matches, send a message specifying a callback too
        chrome.tabs.sendMessage(tab.id, {text: 'report_back'}, doStuffWithDom);
    }
});

content.js:

// Listen for messages
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
    // If the received message has the expected format...
    if (msg.text === 'report_back') {
        // Call the specified callback, passing
        // the web-page's DOM content as argument
        sendResponse(document.all[0].outerHTML);
    }
});

manifest.json:

{
  "manifest_version": 2,
  "name": "Test Extension",
  "version": "0.0",
  ...

  "background": {
    "persistent": false,
    "scripts": ["background.js"]
  },
  "content_scripts": [{
    "matches": ["*://*.stackoverflow.com/*"],
    "js": ["content.js"]
  }],
  "browser_action": {
    "default_title": "Test Extension"
  },

  "permissions": ["activeTab"]
}
147
gkalpak

Il n'est pas nécessaire d'utiliser le message en passant pour obtenir ou modifier DOM. J'ai utilisé chrome.tabs.executeScriptinstead. Dans mon exemple, j'utilise uniquement l'autorisation activeTab. Par conséquent, le script est exécuté uniquement sur l'onglet actif.

partie de manifest.json

"browser_action": {
    "default_title": "Test",
    "default_popup": "index.html"
},
"permissions": [
    "activeTab",
    "<all_urls>"
]

index.html

<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <button id="test">TEST!</button>
    <script src="test.js"></script>
  </body>
</html>

test.js

document.getElementById("test").addEventListener('click', () => {
    console.log("Popup DOM fully loaded and parsed");

    function modifyDOM() {
        //You can play with your DOM here or check URL against your regex
        console.log('Tab script:');
        console.log(document.body);
        return document.body.innerHTML;
    }

    //We have permission to access the activeTab, so we can call chrome.tabs.executeScript:
    chrome.tabs.executeScript({
        code: '(' + modifyDOM + ')();' //argument here is a string but function.toString() returns function's code
    }, (results) => {
        //Here we have just the innerHTML and not DOM structure
        console.log('Popup script:')
        console.log(results[0]);
    });
});
47
Oskar

Pour ceux qui ont essayé gkalpak répondre et cela n'a pas fonctionné,

sachez que chrome ajoutera le script de contenu à une page nécessaire uniquement lorsque votre extension sera activée lors du lancement de chrome et qu'il est également judicieux de redémarrer le navigateur une fois ces modifications apportées.

3
bxN5