当前位置: 首页 > 知识库问答 >
问题:

前端 - 使用plasmo写一个谷歌插件,获取打印预览并自动下载保存pdf?

齐俊达
2026-01-30

我在使用plasmo写一个谷歌插件。目标网站有一个按钮,点击就是打印数据,数据是通过接口获取的。需求是,通过插件批量自动点击打印,把打印预览的,重命名并另存为PDF。现在我发现,我获取不到打印预览弹窗的内容?

共有2个答案

小牛23474
2026-01-30

打印预览是浏览器的功能吧,不是网页功能,在 JS 控制的范围以外。所以你获取不到。

应该没什么解决方法,因为必须调用浏览器 API,没有就是没有。可以考虑换个技术方案,比如走 puppeteer。

小牛24757
2026-01-30

在Plasmo框架中实现自动下载打印预览的PDF,需要绕过Chrome的安全限制。以下是完整方案:

核心问题分析

  1. 打印预览窗口无法直接访问 - Chrome的打印预览是系统级弹窗,无法通过DOM操作获取内容
  2. 需要绕过默认打印流程 - 必须拦截打印请求,生成PDF数据流

解决方案(使用Chrome API)

// background.ts (后台服务)
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action === "savePDF") {
    const { tabId, filename } = request;
    
    // 附加调试器获取PDF数据
    chrome.debugger.attach({ tabId }, "1.0", () => {
      chrome.debugger.sendCommand(
        { tabId },
        "Page.printToPDF",
        {
          transferMode: "ReturnAsBase64",
          printBackground: true,
          landscape: false,
          displayHeaderFooter: false,
          margin: { top: 0.4, bottom: 0.4, left: 0.4, right: 0.4 }
        },
        (pdfData) => {
          if (chrome.runtime.lastError) {
            console.error("PDF生成失败:", chrome.runtime.lastError);
            return;
          }
          
          // 转换并下载PDF
          const pdfBlob = base64ToBlob(pdfData.data, "application/pdf");
          const url = URL.createObjectURL(pdfBlob);
          chrome.downloads.download({
            url: url,
            filename: `${filename}.pdf`,
            saveAs: true
          }, () => URL.revokeObjectURL(url));
          
          chrome.debugger.detach({ tabId });
        }
      );
    });
  }
  return true;
});

function base64ToBlob(base64: string, mimeType: string) {
  const byteCharacters = atob(base64);
  const byteArrays = [];
  for (let offset = 0; offset < byteCharacters.length; offset += 1024) {
    const slice = byteCharacters.slice(offset, offset + 1024);
    const byteNumbers = new Array(slice.length);
    for (let i = 0; i < slice.length; i++) {
      byteNumbers[i] = slice.charCodeAt(i);
    }
    byteArrays.push(new Uint8Array(byteNumbers));
  }
  return new Blob(byteArrays, { type: mimeType });
}
// content.ts (内容脚本)
function automatePrinting() {
  // 1. 找到打印按钮并触发点击
  const printButton = document.querySelector('button.print-btn')!;
  printButton.click();

  // 2. 拦截打印请求
  window.print = () => {
    // 3. 发送生成PDF请求
    chrome.runtime.sendMessage({
      action: "savePDF",
      filename: `report_${new Date().toISOString().slice(0, 10)}`,
      tabId: chrome.devtools.inspectedWindow.tabId
    });
  };
}

// 当数据加载完成后执行
if (document.readyState === 'complete') {
  automatePrinting();
} else {
  window.addEventListener('load', automatePrinting);
}

关键配置

  1. manifest.json 权限声明:

    {
      "permissions": [
     "debugger",
     "downloads",
     "scripting"
      ],
      "host_permissions": ["<target_website>/*"]
    }
  2. plasmo.manifest.json 额外配置:

    {
      "background": {
     "service_worker": "background.ts",
     "type": "module"
      }
    }

实现原理

  1. 拦截打印流程

    • 覆盖window.print()方法阻止默认弹窗
    • 通过点击事件触发自定义打印流程
  2. PDF生成技术

    • 使用chrome.debuggerAPI获取原始PDF数据
    • Page.printToPDF命令生成Base64编码的PDF
  3. 文件下载

    • 转换Base64为Blob对象
    • 通过chrome.downloadsAPI保存文件

注意事项

  1. 用户提示:首次使用需在manifest声明debugger权限,Chrome会显示警告条
  2. 错误处理:添加chrome.debugger的detach操作防止资源泄漏
  3. 样式保留:设置printBackground: true确保CSS样式完整输出
  4. 文件名策略:使用日期/接口数据动态生成文件名(示例中使用日期)

替代方案

如果不想使用debugger API,可考虑:

// 使用html2canvas+jsPDF(有样式失真风险)
import html2canvas from 'html2canvas';
import jsPDF from 'jspdf';

const printElement = document.getElementById('print-area');
html2canvas(printElement).then(canvas => {
  const imgData = canvas.toDataURL('image/png');
  const pdf = new jsPDF('p', 'mm', 'a4');
  pdf.addImage(imgData, 'PNG', 0, 0, 210, 297);
  pdf.save('document.pdf');
});
推荐使用debugger方案,它能完美保留原始打印样式。注意在Chrome 111+版本中,可考虑新的 chrome.printingAPI(目前仅限ChromeOS)。实际部署时需处理网络延迟,建议在接口返回数据后添加500ms延时再触发打印。
 类似资料:
  • 不知道改到哪个地方了,只要点击刷新按钮,谷歌插件就自动打开了,或者是从新打开浏览器,插件也会自动跳出来。有哪位大神知道该怎么改吗

  • 谷歌浏览器调用打印预览,如果去除另存为pdf选项? 希望目标打印机列表 只能选择打印机

  •   最后,我们要给绘图程序增加打印和打印预览功能。我们希望文档分两页打印,第一页为封面,打印文档名字。第二页输出文档内容,并在页眉上打印文档名字。虽然AppWizard已经自动生成了打印和打印预览的代码,但是许多情况下,并不能符合要求。 这是因为: 1.打印机和窗口(屏幕)显示的分辨率不同:打印机的分辨率用每英寸多少个点来描述,屏幕分辨率用单位面积的像素点来表示。对于同样的Arial字体下的一个字

  • 我在尝试从谷歌云存储下载CSV文件时遇到了一个问题。出于某种原因,它一直以字节而不是可读文本的形式下载文件。当我在Excel中打开下载的CSV时,Excel已经足够智能,可以将其转换为可读文本。我在这里错过了什么?我检查了谷歌的文档,但找不到任何好的信息来完成它们。提前谢谢你! 这是错误:UnicodeDecodeError:“utf-8”编解码器无法解码位置15-16的字节:无效的连续字节

  • 我想知道是否有可能从谷歌云存储下载一个文件,它的名称与存储桶中的名称不同。 例如,在谷歌云存储中,我存储了一个名为的文件,但当我下载它时,我想选择一个不同的名称,比如说 我注意到下载的链接是这样的:https://storage.cloud.google.com/bucket_name/123-file.txt?response-内容处置=附件;filename=123-file.txt 因此,我

  • 我已经在谷歌表单中创建了一个自定义表单。当用户按键盘上的[Enter]或[Tab]时,表单上数据字段的顺序与我想跳转到(下一个单元格)的顺序不同。是否有一个方法可以在工作表上使用(不使用谷歌应用程序脚本),我可以指定移动到下一个单元格。

  • 我需要从我的谷歌云存储从我的桶中下载NodeJS文件夹。我读了所有的留档,我只找到了下载文件而不是文件夹的方法。我需要获取/下载文件夹以提供用户的下载文件。 有人能帮我吗?

  • 我是一个非营利组织的谷歌办公套件管理员,刚刚发现了数据导出功能,这似乎就像个人账户的外卖。 导出文件已经准备好,现在可以从谷歌云平台存储中的存储桶下载。然而,有很多很多文件夹,试图进出每个文件夹来下载很多很多。每个文件中的zip文件听起来都是一个令人头疼的问题。 我在Mac上使用Transmit,它可以通过与Amazon S3的互操作性连接到谷歌云存储。然而,当我连接时,我什么也看不到(因为我不使