Skip to content

Executing within Puppeteer (headless browser)

Gildas edited this page Nov 14, 2025 · 2 revisions

Minimum working example (see https://github.com/gildas-lormeau/single-file-cli/discussions/181#discussioncomment-14970620)

import puppeteer from "puppeteer";
import fs from "fs/promises";

import {
  script as SINGLEFILE_SCRIPT,
  hookScript as SINGLEFILE_HOOK,
  zipScript as SINGLEFILE_ZIP
} from "single-file-cli/lib/single-file-bundle.js";

async function capture(url) {
  const browser = await puppeteer.launch({
    headless: true,
    args: [
      "--disable-web-security",
      "--allow-running-insecure-content",
      "--no-sandbox"
    ]
  });

  const page = await browser.newPage();

  await page.evaluateOnNewDocument(SINGLEFILE_HOOK);
  await page.evaluateOnNewDocument(`
    ${SINGLEFILE_SCRIPT}
    window.singlefile = singlefile;
  `);

  await page.goto(url, { waitUntil: "networkidle2", timeout: 60000 });

  await page.evaluate(async () => {
    await new Promise(resolve => {
      let totalScrolled = 0;
      const step = 400;
      const timer = setInterval(() => {
        window.scrollBy(0, step);
        totalScrolled += step;
        if (totalScrolled >= document.body.scrollHeight - window.innerHeight) {
          clearInterval(timer);
          resolve();
        }
      }, 150);
    });
  });

  const title = await page.evaluate(() =>
    (
      document.querySelector("meta[property='og:title']")?.content ||
      document.title ||
      "saved_page"
    ).trim()
  );

  const filename = title.replace(/[^a-z0-9\-_]+/gi, "_") + ".html";

  const result = await page.evaluate(
    async zip => {
      return await window.singlefile.getPageData({
        compressContent: false,
        blockScripts: false,
        blockImages: false,
        blockVideos: false,
        zipScript: zip
      });
    },
    SINGLEFILE_ZIP
  );

  await fs.writeFile(filename, result.content);
  await browser.close();

  console.log("Saved:", filename);
}

const url = process.argv[2];
if (!url) {
  console.error("Usage: node src/capture.js <url>");
  process.exit(1);
}

capture(url).catch(error => {
  console.error("Error:", error.message);
});

Clone this wiki locally