I'm trying to create a chrome extension that scrapes some content from a particular website and then opens a new tab and does stuff with the scraped data.
Below is a test I made to see how I might do this. Unfortunately I can't seem to execute the newtab-script.js file as I get this error:
Unchecked runtime.lastError while running tabs.executeScript: Cannot
access contents of url
"chrome-extension://FAKEIDgfdsgfdsgfdsgdsgfdsgFAKEID/newpage.html".
Extension manifest must request permission to access this host.
at Object.callback (chrome-extension://FAKEIDgfdsgfdsgfdsgdsgfdsgFAKEID/background.js:43:25)
websitescrape.js
var button = document.createElement("button");
button.classList.add("web-scrape");
button.innerHTML = "scrape web";
document.querySelector('.placeIWantToPutButton').appendChild(button);
button.addEventListener('click', scrapeData);
function scrapeData(){
//do website scraping stuff here...
var fakedata = [{test:"data1"},{test:"data2"}];
//send scraped data to background.js
chrome.runtime.sendMessage({setdata: fakedata}, function(tab){
//callback
});
}
background.js
var dataTempStorage = [];
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
if (request.setdata) {
dataTempStorage = request.setdata;
chrome.tabs.create({
'url': chrome.extension.getURL('newpage.html')
}, function(tab) {
chrome.tabs.executeScript(tab.id, {
file:chrome.extension.getURL("newtab-script.js")});
});
}
if (request == "getdata") {
sendResponse({data: dataTempStorage});
}
});
newtab-script.js
chrome.runtime.sendMessage("getdata", function (response) {
doStuff(response.data);
});
function doStuff(){
//Do staff on newpage.html with data scraped from original page
}
newpage.html
// page ready to be filled with awesome content!
Cause: content scripts can't be injected into extension pages with chrome-extension:// scheme.
Solution: since you have control over that html page just reference the content script file explicitly.
newpage.html:
<script src="newtab-script.js"></script>
</body>
</html>
And don't use executeScript.
Related
Let's say there are two websites: x.com and y.com. Here is what I have done so far:
When a button is clicked on x.com, send a message to a background script.
The background script opens a new tab to y.com.
However, now that the tab to y.com has opened, how can I read from the DOM from y.com and use that info in the content script that is running on x.com?
Here is my code so far:
content.js (Content script that runs for x.com)
var btn = document.querySelector('my-btn')
// Send message when btn is clicked
btn.addEventListener('click', message)
function message() {
chrome.runtime.sendMessage({ message: 'Get Y data' }, null, function() {
// I want to use data from `y.com` here somehow
})
}
background.js
chrome.runtime.onMessage.addListener(function(response, sender, sendResponse) {
if (response.message !== 'Get Y data') {
return
}
var url = '...'
chrome.tabs.create({ active: true, url: url }, function (tab) {
// How do I read DOM from this new `tab` and send it back to content script?
})
})
I'm opening a tab and trying to call a function defined in it but i always get a "reference error". I send a message to the script after the script is loaded asking to run "test1" function located on the tab code.
Here is my code:
Extention code
chrome.tabs.executeScript(tab.id, {file: "script.js", runAt: "document_end"}, function(array){
//send message executeTest to the created tab
chrome.tabs.sendMessage(tab.id, {msg: "executeTest"});
});
script.js
url = document.URL;
window.addEventListener("load", doStuff, true);
function doStuff(){
//listen for messages coming from extension
chrome.runtime.onMessage.addListener(
function(message, sender) {
var msg = message.msg;
var url = message.url;
switch(msg){
case "executeTest":
test1();
break;
}
}
);
}
Tab HTML
<head>
<title>Test</title>
</head>
<body>
<script src="app.js"></script>
</body>
</html>
Tab Javascript
function test1(){
console.log("test1 is running!");
}
I receive the message on the script but it's not possible to execute "test1()".
What am i doing wrong ?
A couple of unrelated issues here.
chrome.tabs.sendMessage(tab.id, {msg: executeTest});
executeTest is not a string, it's an (undefined) identifier. That's what throwing the error.
Correct way (ninja'd by user2570380) is to write
chrome.tabs.sendMessage(tab.id, {msg: "executeTest"});
The other problem is that you will not be able to call test1(), because content scripts live in isolated context.
To bypass it, you either need to employ messaging between the webpage and your extension, use externally_connectable, or inject some of your code into the page to trigger what you need.
Considering that you do not control the webpage, you need to inject code in the page's context. Example:
control.js
window.addEventListener("message", function(event) {
// We only accept messages from ourselves
if (event.source != window)
return;
if (event.data.source && (event.data.source == "MyExtension")) {
switch(event.data.command){
case "test1":
test1();
break;
}
}
}, false);
script.js
// Initialization
var s = document.createElement('script');
// TODO: add "control.js" to web_accessible_resources in manifest.json
s.src = chrome.extension.getURL('control.js');
s.onload = function() {
this.parentNode.removeChild(this);
};
(document.head||document.documentElement).appendChild(s);
// Sending a command (make sure script initialized listener first)
window.postMessage({ source: "MyExtension", command: "test1" }, "*");
chrome.tabs.sendMessage(tab.id, {msg: "executeTest"});
Quotes.
I want to run a content script to identify the first image that links somewhere and return the link to the background script. But I can't pass any messages between them, and I don't know why. Much of the code is comment, I'm trying to simply test if the content script is executing by telling it to change the first header to "test" (since the only thing I can do without messages is change a page's HTML and CSS). The code follows:
EDIT: full updated code
Background script:
chrome.browserAction.onClicked.addListener(function () {
chrome.tabs.query({active:true, currentWindow:true}, function(tabs)
{
chrome.tabs.executeScript(tabs[0].id, {file:"content.js"}, function ()
{
console.log("sending first time");
console.log(tabs[0].id);
chrome.tabs.sendMessage(tabs[0].id,{test: "test"}, function (response)
{
if (undefined == response)
{
console.log ("first one didn't work");
chrome.tabs.sendMessage(tabs[0].id, {test: "test"}, function (response)
{
console.log(response.test);
});
}
});
});
});
});
Content Script:
chrome.runtime.onMessage.addListener( function (msg, sender, sendResponse)
{
/*var test1 = document.getElementsByTagName("h1")[0];
test1.innerHTML="test";*/
sendReponse({test: "123"});
/*var parentList =document.getElementsByTagName("a");
var link = "";
var child;
for (var i=2; i<parentList.length;i++)
{
child=parentList[i].firstChild;
if ("IMG"==child.nodeName)
{
link=parentList[i].href;
break;
}
}
teste1.innerHTML=link;
var answer = new Object();
Answer.link = link;
teste1.innerHTML=answer.link;
sendResponse({messager:answer});*/
});
I was testing the extension at the extension page itself. But it seems you can't inject javascript in it (probably because it is a browser's settings page). It worked nicely on other pages.
I've created a chrome extension that consists of manifest.json, content.js and background.js. in content.js, I'm extracting the current tab's URL and in background.js, I'm opening a new tab. what I want to do, which doesn't work is to pass the URL from content and append it to the URL that I'm calling in background.
content.js:
chrome.extension.onMessage.addListener(function(request, sender, sendResponse)
{
if(request.greeting=="gimmieyodatas")
{
var output ="URL=";
//check for the character '?' for any parameters in the URL
var paramIndex = document.URL.indexOf("?");
//if found, eliminate the parameters in the URL
if (paramIndex > -1)
{
output += document.URL.substring(0, paramIndex);
};
sendResponse({data: output});
}
else{
sendResponse({});
}
});
background.js:
var output2;
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendMessage(tab.id, {greeting:"gimmieyodatas"}, function(response) {
output2 = response.data;
});
});
chrome.browserAction.onClicked.addListener(function() {
chrome.tabs.create({url: "http://www.google.com?" + output2}, function(tab) {
chrome.tabs.executeScript(tab.id, {file: "content.js"}, function() {
sendMessage();
});
});
});
When I run the extension from an open tab, it opens google on a new tab, but it doesn't append the current tab's URL in google URL, meaning the 'output' data does not get passed to the background.js. What am I doing wrong?
The problem is that you are not telling the background page to send a message when a new tab is opened. The call to chrome.tabs.getSelected only happens once when the extension is first run -- it does not happen every time a new tab is opened.
You're on the right track by using the background page as an intermediary between the two content pages, but I suggest a different approach:
Load the content script every time a new tab is opened, via the manifest file:
"content_scripts": [
{
"matches" : [
"<all_urls>"
],
"js" : [
"content.js"
]
}
],
Use a much simpler content script that just sends a message to the background with the current URL page as soon as it loads:
(content.js)
var paramIndex = document.URL.indexOf('?');
if (paramIndex > -1) {
chrome.runtime.sendMessage({output2: 'URL=' + document.URL.substring(0, paramIndex)});
}
When the background page receives the message it saves the URL to a global variable:
(background.js)
var output2;
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
output2 = request.output2;
});
You can then load that URL when the action button is clicked:
(background.js)
chrome.browserAction.onClicked.addListener(function() {
chrome.tabs.create({url: "http://www.google.com?" + output2});
});
Having a problem while passing messages using content scripts in Google chrome extension dev
My Code structure looks like this:
popup.html:
var oList;
function getHTML()
{
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, {action:"getHTML"}, function handler(response) {
oList = response.dom;
});
});
alert("oList = "+oList );
}
and my content Script looks like this:
chrome.extension.onRequest.addListener(
function(request, sender, sendResponse) {
if(request.action == "getHTML"){
sendResponse({dom: document.getElementsByTagName("HTML").length});
}
});
When I debug my code by putting a breakpoint at "oList = response.dom;" in my popup.html, i get the
right value set from the content script. But while executing the extension, the "alert("oList = "+oList );" code
from the popup.html seems to be executing first before it goes to the server.. And therefore, its value is
not being set.. Can somebody tell me if I am wrong somewhere ?
Most Chrome API methods are asynchronous. It means that when you are calling them the script doesn't wait for their response and simply continues executing. If you want to execute something on response you should put it inside callback function:
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, {action:"getHTML"}, function handler(response) {
oList = response.dom;
alert("oList = "+oList );
});
});