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

如何在Google Apps Script中将外部CSS转为行内样式导出正确PDF

解决方案

这个需求完全可实现,你遇到的渲染异常属于Google Apps Script内置HTML转PDF接口的已知限制:该接口仅识别元素的行内style属性,不会解析头部的外部CSS引用和<style>标签内的样式,因此需要先把所有样式转换为行内样式再生成PDF。

以下是修改后的完整可运行代码:

function downloadFile() {
  const fileURL = "你的HTML页面地址";
  const targetFolderId = "1gBA8YCs3PH7v7CNl3nlsjNqYzhOxhjYa";
  let fileName = "";
  let fileSize = "";

  // 拉取原始HTML内容
  const response = UrlFetchApp.fetch(fileURL, {
    headers: { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() },
  });
  const htmlBody = response.getContentText();
  const rc = response.getResponseCode();

  if (rc == 200) {
    // 第一步:提取所有外部CSS链接并拉取样式内容
    const cssLinks = htmlBody.match(/<link[^>]+rel="stylesheet"[^>]+href="([^"]+)"/gi) || [];
    let allCss = "";
    cssLinks.forEach(linkTag => {
      const cssUrl = linkTag.match(/href="([^"]+)"/)[1];
      // 补全相对路径的CSS地址(如果你的页面用了相对路径)
      const absoluteCssUrl = cssUrl.startsWith("http") ? cssUrl : new URL(cssUrl, fileURL).href;
      try {
        const cssRes = UrlFetchApp.fetch(absoluteCssUrl);
        allCss += cssRes.getContentText() + "\n";
      } catch(e) {
        console.log("拉取CSS失败:" + absoluteCssUrl, e);
      }
    });

    // 第二步:提取页面内部<style>标签的样式
    const innerStyles = htmlBody.match(/<style[^>]*>([\s\S]*?)<\/style>/gi) || [];
    innerStyles.forEach(styleTag => {
      const styleContent = styleTag.replace(/<\/?style[^>]*>/gi, "").trim();
      allCss += styleContent + "\n";
    });

    // 第三步:调用样式转行内工具处理HTML
    const processedHtml = convertCssToInline(htmlBody, allCss);

    // 第四步:用处理后的HTML生成PDF
    const blob = Utilities.newBlob(processedHtml, MimeType.HTML).getAs('application/pdf').setName('Nota.pdf');
    const folder = DriveApp.getFolderById(targetFolderId);
    if(folder != null){
      const file = folder.createFile(blob);
      fileName = file.getName();
      fileSize = file.getSize();
    }
  }
  const fileInfo = {'rc':rc,"filename": fileName, "fileSize":fileSize}
  Logger.log(fileInfo)
}

// 辅助函数:将CSS转换为对应元素的行内样式
function convertCssToInline(html, css) {
  // 移除原HTML中的link和style标签,避免重复加载
  html = html.replace(/<link[^>]+rel="stylesheet"[^>]*>/gi, "");
  html = html.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "");

  // 基础CSS规则解析,复杂选择器可根据需求扩展
  const cssRules = css.match(/[^}]+{[^}]+}/g) || [];
  cssRules.forEach(rule => {
    const parts = rule.split("{");
    const selector = parts[0].trim();
    const styles = parts[1].replace("}", "").trim();
    if (!selector || !styles) return;

    // 匹配所有符合选择器的元素,添加行内样式
    const regex = new RegExp(`(<${selector}[^>]*)>`, "gi");
    html = html.replace(regex, (match, prefix) => {
      // 如果已有style属性则追加样式,无则新增
      if (prefix.includes("style=")) {
        return prefix.replace(/style="([^"]*)"/, `style="$1;${styles}"`) + ">";
      } else {
        return `${prefix} style="${styles}">`;
      }
    });
  });
  return html;
}

注意事项

  • 上述辅助函数的CSS选择器解析逻辑默认支持基础的元素选择器,如需支持类选择器、ID选择器,可自行扩展convertCssToInline函数的匹配规则即可。
  • 如果页面样式依赖JavaScript动态渲染,需要先处理动态内容再转换样式,可通过调整拉取页面的逻辑实现。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 09:18:01