Tiện ích mở rộng Chrome - Nhận nội dung DOM


116

Tôi đang cố gắng truy cập nội dung DOM ActiveTab từ cửa sổ bật lên của mình. Đây là bản kê khai của tôi:

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

Tôi thực sự bối rối không biết tập lệnh nền (các trang sự kiện có tính kiên trì: false) hay content_scripts là cách để đi. Tôi đã đọc tất cả các tài liệu và các bài đăng SO khác và nó vẫn không có ý nghĩa gì đối với tôi.

Ai đó có thể giải thích tại sao tôi có thể sử dụng cái này hơn cái kia không.

Đây là background.js mà tôi đang thử:

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

Và tôi chỉ thực hiện điều này từ bảng điều khiển bật lên:

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

Tôi nhận được:

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

CẬP NHẬT:

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

Khi tôi chạy nó, tôi vẫn gặp lỗi tương tự:

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

Câu trả lời:


184

Các thuật ngữ "trang nền", "cửa sổ bật lên", "kịch bản nội dung" vẫn khiến bạn bối rối; Tôi thực sự khuyên bạn nên xem xét chuyên sâu hơn Tài liệu về tiện ích mở rộng của Google Chrome .

Về câu hỏi của bạn nếu tập lệnh nội dung hoặc trang nền là cách để đi:

Tập lệnh nội dung : Chắc chắn Tập
lệnh nội dung là thành phần duy nhất của tiện ích mở rộng có quyền truy cập vào DOM của trang web.

Trang nền / Cửa sổ bật lên : Có thể (có thể là tối đa 1 trong hai)
Bạn có thể cần tập lệnh nội dung chuyển nội dung DOM đến trang nền hoặc cửa sổ bật lên để xử lý thêm.


Hãy để tôi nhắc lại rằng tôi thực sự khuyên bạn nên nghiên cứu kỹ hơn các tài liệu có sẵn!
Điều đó nói rằng, đây là một tiện ích mở rộng mẫu lấy nội dung DOM trên các trang StackOverflow và gửi nó đến trang nền, sau đó sẽ in nó trong bảng điều khiển:

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.sendMessagegửi tin nhắn đến Trang nền và cửa sổ bật lên. chrome.tabs.sendMessagegửi tin nhắn đến ContentScripts.
gkalpak

22
Đã phản đối vì câu trả lời này không giải thích cách lấy DOM ACTUAL từ tab hiện tại.
John Paul Barbagallo,

2
@JohnPaulBarbagallo: Câu hỏi là về việc lấy nội dung DOM, không phải về việc truy cập / thao tác DOM thực. Tôi nghĩ câu trả lời của tôi làm được điều đó (và những người khác dường như cũng nghĩ như vậy). Nếu bạn có một giải pháp tốt hơn, hãy đăng nó như một câu trả lời. Nếu bạn có một yêu cầu khác, hãy đăng nó dưới dạng một câu hỏi mới. Trong mọi trường hợp, thx cho ý kiến phản hồi :)
gkalpak

2
@zoltar: Nó được in trong bảng điều khiển của trang nền.
gkalpak

2
Tôi đã sao chép / paster câu trả lời này nhưng không thể nhận được bất kỳ dạng tập lệnh nội dung nào của console.log. xin hãy giúp đỡ!
ClementWalter

72

Bạn không cần phải sử dụng thông điệp chuyển để lấy hoặc sửa đổi DOM. Tôi đã sử dụng chrome.tabs.executeScriptthay thế. Trong ví dụ của tôi, tôi chỉ sử dụng quyền activeTab, do đó, tập lệnh chỉ được thực thi trên tab hoạt động.

một phần của 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]);
    });
});

1
Hoạt động hoàn hảo! Cảm ơn bạn. Tôi không biết tại sao nhưng tôi không thể làm cho giải pháp được chấp nhận phù hợp với tôi.
goodfellow

Tuyên bố của bạn rằng bạn chỉ sử dụng activeTabquyền là không chính xác. Bạn rõ ràng đang nhận được <all_urls>thêm vào activeTab.
Makyen

1
test.js là tập lệnh bạn đã đưa vào HTML của trang, vì vậy tôi không chắc bạn cần bất kỳ quyền nào .
Scott Baker

11

Đối với những người đã thử câu trả lời của gkalpak và nó không hoạt động,

lưu ý rằng chrome sẽ chỉ thêm tập lệnh nội dung vào một trang cần thiết khi tiện ích mở rộng của bạn được bật trong khi khởi chạy chrome và bạn cũng nên khởi động lại trình duyệt sau khi thực hiện những thay đổi này


1
Điều này đã cứu một ngày của tôi
Romain Derie
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.