首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在Chrome扩展的后台加载网页?

如何在Chrome扩展的后台加载网页?
EN

Stack Overflow用户
提问于 2022-02-12 10:40:16
回答 1查看 1.1K关注 0票数 1

我正在编写一个Chrome扩展,它将根据来自另一个网页的内容(在另一个域上)向页面添加一些信息。

这是通过要求后台服务工作人员加载页面,然后将相关信息传递回内容脚本来完成的。

重要的是页面被加载,就像用户打开一个带有该页面的选项卡一样,所以它将使用用户的登录和其他上下文(locale等)。

content.js

代码语言:javascript
运行
复制
chrome.runtime.sendMessage('some-query', function(response) {
  console.log(response)
})

background.js

代码语言:javascript
运行
复制
chrome.runtime.onMessage.addListener((message, sender, reply) => {
  loadInBackground(message, reply)
  return true
})

function loadInBackground(query, reply) {
  console.log('searching for', query)
  let url = new URL("https://some.site.com/search")
  url.searchParams.append("query", query)
  // How to load the page?
  reply('data-from-loaded-page')
}

我尝试过使用fetch,但这会产生CORS错误,即使没有,我也不希望它像加载在选项卡中一样使用状态。那么,我能用什么隐藏的Chrome来完成这个任务呢?我看过所有这些,但找不到我需要的API。

EN

回答 1

Stack Overflow用户

发布于 2022-02-12 16:05:50

若要在扩展脚本中使用fetch,请将该URL或"<all_urls>"添加到主机权限中。

但是还有一个更大的问题:站点的脚本不能使用fetch运行,因此在许多动态构造自己的现代页面上提取没有什么有用的。

在这种情况下,扩展的唯一解决办法是在一个新的选项卡或iframe中打开该站点,因为Chrome扩展不像Chrome那样具有WebView,因此扩展不能完全模拟正常的页面加载过程。请注意,Chrome应用程序不久将不再存在于Chrome中。

在一个新的选项卡中打开站点的问题是它对用户是可见的。您可以通过打开一个新的非聚焦窗口(chrome.windows.create)来减少烦恼,但这也会对许多用户产生一些视觉效果,这取决于他们的桌面环境。

因此,唯一不显眼的解决方法是创建指向远程页面的iframe。

  1. 在原始网页中创建一个资源-exposed iframe,因为MV3扩展在后台脚本中没有DOM。对于此任务,您根本不需要后台脚本。iframe可以“隐藏”在关闭的ShadowDOM中的页面中。这个iframe将完全访问所有授予的chrome API。
  2. 可以选择注册一个标题
  3. 添加一个子iframe,其中src指向要获取的站点。
  4. 使用executeScript提取数据,并使用通过webRequest获得的frameId。
  5. 将数据发送到主内容脚本。

manifest.json:

代码语言:javascript
运行
复制
  "host_permissions": ["<all_urls>"],
  "permissions": ["declarativeNetRequestWithHostAccess", "scripting", "webRequest"],
  "web_accessible_resources": [{
    "resources": ["iframer.html"],
    "matches": ["<all_urls>"]
  }],

主要内容脚本:

代码语言:javascript
运行
复制
(async () => {
  const data = await getRemoteSiteData('https://www.example.com', ['body']);
  console.log(data);
})();

function getRemoteSiteData(url, selectors) {
  const id = Math.random().toString(36).slice(2);
  const iframe = document.createElement('iframe');
  const el = document.createElement('div');
  const root = el.attachShadow({mode: 'closed'});
  root.appendChild(document.createElement('style')).textContent =
    ':host { display: none !important }';
  root.appendChild(iframe);
  iframe.src = chrome.runtime.getURL('iframer.html#' + id);
  document.body.appendChild(el);
  return new Promise(resolve => {
    chrome.runtime.onMessage.addListener(function _(msg, sender, sendResponse) {
      if (msg.id !== id) return;
      if (msg.init) {
        sendResponse({url, selectors, frameId: sender.frameId});
      } else {
        el.remove();
        chrome.runtime.onMessage.removeListener(_);
        resolve(msg.result);
      }
    });
  });
}

iframer.html:

代码语言:javascript
运行
复制
<script src=iframer.js></script>

iframer.js:

代码语言:javascript
运行
复制
(async () => {
  const id = location.hash.slice(1);
  const tabId = (await chrome.tabs.getCurrent()).id;
  const job = await chrome.tabs.sendMessage(tabId, {id, init: true});
  const iframe = document.createElement('iframe');
  let webFrameId;
  chrome.webRequest.onBeforeRequest.addListener(function _(info) {
    chrome.webRequest.onBeforeRequest.removeListener(_);
    webFrameId = info.frameId;
  }, {tabId, types: ['sub_frame']});
  iframe.src = job.url;
  document.body.appendChild(iframe);
  await new Promise(onload => Object.assign(iframe, {onload})); 
  const data = await chrome.scripting.executeScript({
    target: {tabId, frameIds: [webFrameId]},
    args: [job.selectors],
    func: selectors => selectors.map(sel =>
      Array.from(document.querySelectorAll(sel),
        el => el.textContent)),
  })
  const {result} = data.find(d => d.frameId === webFrameId);
  await chrome.tabs.sendMessage(tabId, {id, result}, {frameId: job.frameId});
})();
  • 警告! http:// URL无法加载到https://站点上。您将看到devtools控制台中的混合内容被阻塞的错误。唯一的解决办法是将上面的步骤1替换为为远程站点打开一个新的选项卡/窗口,并在那里运行一个内容脚本,例如,原始内容脚本向使用chrome.tabs.create + chrome.scripting.executeScript的后台脚本发送一条消息。
  • 警告!一些站点使用JS通过检查window == window.top来停止在iframes中加载。 如果该检查是在内联script元素中完成的,则不能欺骗它。
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71091125

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档