Розширення Chrome - отримуйте вміст DOM


116

Я намагаюся отримати доступ до вмісту DOM ActiveTab зі свого спливаючого вікна. Ось мій маніфест:

{
  "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"
  }
}

Я дуже заплутаний, чи фонові сценарії (сторінки подій із наполегливістю: false) або content_scripts - це шлях. Я прочитав усю документацію та інші повідомлення SO, і це все ще не має для мене сенсу.

Хтось може пояснити, чому я можу використовувати один над іншим.

Ось background.js, який я намагався:

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

І я просто виконую це з всплывающей консолі:

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

Я отримую:

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

ОНОВЛЕННЯ:

{
  "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.innerHTML });
    }
  }
);

popup.html

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

Коли я запускаю його, я все одно отримую ту саму помилку:

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

Відповіді:


183

Терміни "фонова сторінка", "спливаюче вікно", "скрипт вмісту" все ще бентежать вас; Настійно пропоную більш детально ознайомитися з Документацією щодо розширень Google Chrome .

Що стосується вашого запитання, чи вміють сценарії вмісту або фонові сторінки:

Сценарії вмісту : Безперечно,
сценарії вмісту є єдиним компонентом розширення, що має доступ до DOM веб-сторінки.

Фонова сторінка / Спливаюче вікно: Можливо (можливо, максимум 1 з двох)
Можливо, вам знадобиться, щоб сценарій вмісту передав вміст DOM або на фонову сторінку, або на спливаюче вікно для подальшої обробки.


Повторюся, що настійно рекомендую більш ретельно вивчити наявну документацію!
З цього приводу, ось зразкове розширення, яке отримує вміст DOM на сторінках StackOverflow та надсилає його на фонову сторінку, яка, у свою чергу, друкує його в консолі:

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"]
}

6
@solvingPuzzles: chrome.runtime.sendMessageнадсилає повідомлення на BackgroundPage і на спливаючі вікна. chrome.tabs.sendMessageнадсилає повідомлення до ContentScripts.
gkalpak

23
Незважаючи на те, що ця відповідь не пояснює, як отримати АКТУАЛЬНИЙ ДОМ з поточної вкладки.
Джон Пол Барбагалло

2
@JohnPaulBarbagallo: Питання полягало у тому, щоб отримати вміст DOM, а не про доступ / маніпулювання фактичним DOM. Я думаю, що моя відповідь робить це (а інші, здається, думають так само). Якщо у вас є краще рішення, опублікуйте це як відповідь. Якщо у вас є інша вимога, опублікуйте це як нове запитання. У будь-якому випадку, thx для зворотного зв’язку :)
gkalpak

2
@zoltar: Друкується на консолі фонової сторінки.
гкалпак

2
У мене є відповідь "копіювати / вставляти", але не можу отримати жоден console.log форму вмісту сценарію. Допоможіть, будь ласка!
ClementWalter

72

Вам не потрібно використовувати повідомлення, що передаються, щоб отримати або змінити DOM. Я використовував chrome.tabs.executeScriptзамість цього. У своєму прикладі я використовую лише дозвіл activeTab, тому сценарій виконується лише на активній вкладці.

частина маніфесту.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]);
    });
});

1
Працює чудово! Дякую. Я не знаю, чому, але я не зміг зробити так, щоб прийняте рішення працювало для мене.
goodfellow

Ваша заява про те, що ви використовуєте лише activeTabдозвіл, є неточною. Ви, очевидно, отримуєте <all_urls>на додаток до activeTab.
Макіен

1
test.js - це сценарій, який ви включили до HTML вашої сторінки, тому я не впевнений, що вам потрібні будь-які дозволи.
Скотт Бейкер

11

Для тих, хто спробував відповісти gkalpak, але це не вийшло,

майте на увазі, що chrome додасть скрипт вмісту на потрібну сторінку лише тоді, коли розширення ввімкнено під час запуску Chrome, а також гарну ідею перезапустити браузер після внесення цих змін


1
Це врятувало мені день
Ромен Дері
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.