You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Chrome扩展中如何延迟fetch()直至目标网站动态内容加载完成?

解决Chrome扩展中等待动态页面加载后抓取源码的问题

嘿,我明白你现在的困扰:直接用fetch()请求smmry.com的页面只能拿到初始骨架,动态渲染的内容根本抓不到对吧?这是因为动态内容是页面加载后通过JS生成的,fetch只能获取服务器返回的静态HTML。下面给你两种靠谱的实现方式,帮你等到动态内容加载完再保存完整页面。

方案1:监听DOM变化的智能等待(首推)

这种方法会盯着目标页面的DOM变化,直到页面停止更新一小段时间再抓取,比固定延迟灵活多了,适配各种网络速度。

第一步:更新扩展权限

先把manifest.json里的权限补全,不然没法注入脚本和下载文件:

{
  "manifest_version": 3,
  "name": "Smmry页面保存工具",
  "version": "1.0",
  "action": {
    "default_icon": "icon.png"
  },
  "permissions": ["activeTab", "scripting", "downloads"],
  "host_permissions": ["https://smmry.com/*"]
}

第二步:替换点击事件逻辑

把你原来的立即执行代码换成下面的逻辑(可以放在background.js或者弹窗脚本里):

chrome.action.onClicked.addListener(async (tab) => {
  // 拼接smmry的目标URL,注意编码原标签页的URL
  const smmryUrl = `https://smmry.com/${encodeURIComponent(tab.url)}`;

  try {
    // 打开smmry页面,然后注入等待脚本
    const newTab = await chrome.tabs.create({ url: smmryUrl });
    const [result] = await chrome.scripting.executeScript({
      target: { tabId: newTab.id },
      func: waitForContentLoad,
      args: [500] // 等待DOM停止更新的时间(毫秒),可按需调整
    });

    // 把抓取到的完整HTML转成Blob并触发下载
    const blob = new Blob([result.result], { type: 'text/html' });
    const downloadUrl = URL.createObjectURL(blob);
    await chrome.downloads.download({
      url: downloadUrl,
      filename: `smmry-${new Date().toISOString().slice(0,10)}.html`,
      saveAs: true
    });
  } catch (err) {
    console.error('抓取失败:', err);
    alert('哎呀,抓取页面出错了,再试一次吧!');
  }
});

// 这个函数会被注入到smmry页面里,负责等待动态内容加载
function waitForContentLoad(idleDelay) {
  return new Promise(resolve => {
    let timeoutId;
    // 监听DOM的所有变化
    const observer = new MutationObserver(() => {
      // 每次DOM变了就重置计时器,确保等页面完全稳定
      clearTimeout(timeoutId);
      timeoutId = setTimeout(() => {
        observer.disconnect(); // 停止监听
        resolve(document.documentElement.outerHTML); // 返回完整页面源码
      }, idleDelay);
    });

    // 开始监听整个文档的变化(包括子节点、属性)
    observer.observe(document.documentElement, {
      childList: true,
      subtree: true,
      attributes: true
    });

    // 兜底计时器:如果页面一开始就没DOM变化,到点就直接返回
    timeoutId = setTimeout(() => {
      observer.disconnect();
      resolve(document.documentElement.outerHTML);
    }, idleDelay);
  });
}

方案2:固定延迟(简单但不够灵活)

如果你的网络环境比较稳定,smmry的加载时间基本固定,也可以用setTimeout来硬等,代码更简单:

chrome.action.onClicked.addListener(async (tab) => {
  const smmryUrl = `https://smmry.com/${encodeURIComponent(tab.url)}`;
  const newTab = await chrome.tabs.create({ url: smmryUrl });

  // 等3秒再抓取(根据实际加载时间调整这个数值)
  setTimeout(async () => {
    try {
      const [result] = await chrome.scripting.executeScript({
        target: { tabId: newTab.id },
        func: () => document.documentElement.outerHTML
      });

      const blob = new Blob([result.result], { type: 'text/html' });
      const downloadUrl = URL.createObjectURL(blob);
      await chrome.downloads.download({
        url: downloadUrl,
        filename: `smmry-${new Date().toISOString().slice(0,10)}.html`,
        saveAs: true
      });
    } catch (err) {
      console.error('抓取失败:', err);
      alert('出错啦,重试一下吧!');
    }
  }, 3000);
});

重要提醒

  • 为啥不能直接用fetch()?因为smmry.com的核心内容是页面加载后用JS渲染出来的,fetch只能拿到服务器发的空骨架,根本看不到渲染后的内容。
  • 脚本注入的好处:注入的代码是在目标页面的上下文里运行的,能直接访问到完整的渲染后DOM。
  • 权限一定要加全:activeTab让你能操作当前标签,scripting允许注入脚本,downloads能触发文件下载。

内容的提问来源于stack exchange,提问作者Foobar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:30:17