Heim Web-Frontend js-Tutorial So erfassen Sie Webseiten-Screenshots mit Next.js und Puppeteer

So erfassen Sie Webseiten-Screenshots mit Next.js und Puppeteer

Nov 04, 2024 am 07:44 AM

How to Capture Web Page Screenshots with Next.js and Puppeteer

Das programmgesteuerte Erfassen von Screenshots von Webseiten kann unglaublich nützlich sein, um Vorschauen zu erstellen, bildbasierte Berichte zu erstellen und mehr. In dieser Anleitung erstellen wir eine Next.js-API-Route, die eine URL verwendet und einen PNG-Screenshot generiert. Unser Setup nutzt Puppeteer und chrome-aws-lambda, um einen Headless-Chrome-Browser zu nutzen und ihn so vielseitig und produktionsbereit zu machen.

Wir beginnen mit der Einrichtung eines neuen Next.js-Projekts und gehen den Code Schritt für Schritt durch, um zu verstehen, wie die API Screenshots erfasst.

Voraussetzungen

  • Einrichten der Next.js-App
  • API-Route mit Puppeteer konfigurieren
  • Erstellen der React-Komponente für die Capture-Schnittstelle
  • Erläuterung der lokalen vs. Bereitstellungskonfigurationen für Puppeteer

Erste Schritte mit einem neuen Next.js-Projekt

  1. Erstellen Sie eine neue Next.js-App:
npx create-next-app@latest capture-image-app
cd capture-image-app
Nach dem Login kopieren
  1. Installieren Sie die erforderlichen Abhängigkeiten:
npm install puppeteer puppeteer-core chrome-aws-lambda busboy
Nach dem Login kopieren

Schritt 2: Erstellen Sie die API-Route zum Generieren von Screenshots

Jetzt richten wir einen API-Endpunkt ein, um Screenshots basierend auf einer bereitgestellten URL zu erfassen und zurückzugeben.

Erstellen Sie im Ordner „pages/api“ eine neue Datei mit dem Namen „generate-png.ts“ und fügen Sie diesen Code hinzu:

import { NextApiRequest, NextApiResponse } from "next";
import busboy, { Busboy } from "busboy"; // Use busboy for multipart parsing
import chromium from "chrome-aws-lambda";
import puppeteerCore from "puppeteer-core"; // Import puppeteer-core directly
import puppeteer from "puppeteer"; // Import puppeteer directly

// Conditional import for Puppeteer based on the environment
const puppeteerModule = process.env.NODE_ENV === "production" ? puppeteerCore : puppeteer;

export const config = {
  api: {
    bodyParser: false, // Disable default body parsing to handle raw binary data (Blob)
  },
};

const delay = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
): Promise<void> {
  try {
    if (req.method === "POST") {
      const bb: Busboy = busboy({ headers: req.headers });
      let width: number = 1920; // Default width
      let height: number = 0; // Default height
      let delayTime: number = 6000;
      const buffers: Buffer[] = [];

      bb.on("file", (_name: string, file: NodeJS.ReadableStream) => {
        file.on("data", (data: Buffer) => buffers.push(data));
      });

      bb.on("field", (name: string, value: string) => {
        if (name === "width") width = parseInt(value, 10) || 1920;
        if (name === "height") height = parseInt(value, 10) || 0;
        if (name === "delay") delayTime = parseInt(value, 10) || 6000;
      });

      bb.on("finish", async () => {
        const blobBuffer: Buffer = Buffer.concat(buffers);
        const htmlContent: string = blobBuffer.toString("utf-8");

        const browser = await puppeteerModule.launch({
          args: ["--start-maximized"],
          executablePath: process.env.NODE_ENV === "production"
            ? await chromium.executablePath || "/usr/bin/chromium-browser"
            : undefined,  // No custom executable path needed for local
          headless: true,
        });

        const page = await browser.newPage();

        // Load the HTML content directly
        await page.setContent(htmlContent, { waitUntil: "networkidle0" });

        //@ts-expect-error todo
        const bodyHeight = await page.evaluate(() => {
          return document.body.scrollHeight; // Get the full scrollable height of the body
        });

        await page.setViewport({
          width: Number(width),
          height: height || bodyHeight, // Use the provided height or fallback to the full body height
          deviceScaleFactor: 2,
        });

        await delay(delayTime);

        const screenshotBuffer = await page.screenshot({
          fullPage: !height,
          type: "png",
          omitBackground: false,
        });

        await browser.close();

        res.setHeader("Content-Type", "image/png");
        res.setHeader(
          "Content-Disposition",
          "attachment; filename=screenshot.png"
        );
        res.status(200).end(screenshotBuffer);
      });

      req.pipe(bb); // Pipe the request stream to busboy
    } else {
      res.setHeader("Allow", ["POST"]);
      res.status(405).end(`Method ${req.method} Not Allowed`);
    }
  } catch (error) {
    console.error("ERROR", error);
    res.status(500).end("Internal Server Error");
  }
}


Nach dem Login kopieren

*Erläuterung: Auswahl von Puppeteer für lokale oder Produktionsumgebungen
*

In diesem Code haben wir einen dynamischen Import für Puppenspieler eingerichtet:

  • Lokale Entwicklung: Wenn NODE_ENV keine Produktion ist, wird Puppeteer verwendet, was einfacher einzurichten ist und kein Chrome-AWS-Lambda erfordert.

  • Produktion: Bei serverlosen Bereitstellungen erkennt die Umgebung NODE_ENV als Produktion und lädt puppeteer-core zusammen mit chrome-aws-lambda, was die Arbeit in AWS Lambda und anderen ähnlichen Umgebungen ermöglicht. In diesem Setup stellt chrome-aws-lambda den richtigen Chromium-Pfad bereit und gewährleistet so die Kompatibilität mit serverlosen Anbietern.

Schritt 3: Erstellen Sie eine einfache Reaktionskomponente für die Benutzeroberfläche

Hier erstellen wir ein einfaches Formular, mit dem Benutzer Werte für die Webseitenerfassung eingeben können. Dieses Formular löst die Generierungsfunktion aus, um den Screenshot im PDF-Format zu erfassen und herunterzuladen.

import { useState } from "react";

export default function ScreenCaptureComponent() {
  const [isProcessing, setProcessing] = useState(false);
  const [width, setWidth] = useState<string>("1920");
  const [height, setHeight] = useState<string>("1000");
  const [delay, setDelay] = useState<string>("6000");

  // Function to clone HTML and prepare for capture
  function takeScreenshot() {
    const clonedElement = document.body.cloneNode(true) as HTMLElement;
    const blob = new Blob([clonedElement.outerHTML], { type: "text/html" });
    return blob;
  }

  // Function to capture screenshot by sending cloned HTML to API
  async function generateCapture() {
    setProcessing(true);

    const htmlBlob = takeScreenshot();

    if (!htmlBlob) {
      setProcessing(false);
      return;
    }

    try {
      const formData = new FormData();
      formData.append("file", htmlBlob);
      formData.append("width", width);
      formData.append("height", height);
      formData.append("delay", delay);
      const response = await fetch("/api/generate-png", {
        method: "POST",
        body: formData,
      });

      if (!response.ok) throw new Error("Capture failed");

      const blob = await response.blob();
      const downloadUrl = URL.createObjectURL(blob);
      const link = document.createElement("a");
      link.href = downloadUrl;
      link.download = "capture.png";
      link.click();
      URL.revokeObjectURL(downloadUrl);
    } catch (error) {
      console.error("Failed to capture screenshot", error);
    } finally {
      setProcessing(false);
    }
  }

  return (
    <div
      style={{
        maxWidth: "400px",
        margin: "50px auto",
        padding: "24px",
        backgroundColor: "white",
        borderRadius: "8px",
        width: "100%",
        boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)",
      }}
    >
      <h2
        style={{
          fontSize: "24px",
          fontWeight: "600",
          textAlign: "center",
          marginBottom: "16px",
        }}
      >
        Webpage Screenshot Capture
      </h2>
      <form
        onSubmit={(e) => {
          e.preventDefault();
          generateCapture();
        }}
        style={{
          display: "flex",
          flexDirection: "column",
          alignItems: "center",
          marginBottom: "16px",
        }}
      >
        <label
          style={{ marginBottom: "8px", fontWeight: "500" }}
          htmlFor="width"
        >
          Width (px)
        </label>
        <select
          id="width"
          value={width}
          onChange={(e) => setWidth(e.target.value)}
          style={{
            width: "100%",
            padding: "8px",
            marginBottom: "16px",
            borderRadius: "4px",
            border: "1px solid #ccc",
            outline: "none",
          }}
        >
          <option value="1920">1920 (Full HD)</option>
          <option value="1366">1366 (Laptop)</option>
          <option value="1280">1280 (Desktop)</option>
          <option value="1024">1024 (Tablet Landscape)</option>
          <option value="768">768 (Tablet Portrait)</option>
          <option value="375">375 (Mobile)</option>
        </select>

        <label
          style={{ marginBottom: "8px", fontWeight: "500" }}
          htmlFor="height"
        >
          Height (px)
        </label>
        <input
          type="number"
          id="height"
          value={height}
          onChange={(e) => setHeight(e.target.value)}
          required
          style={{
            width: "100%",
            padding: "8px",
            marginBottom: "16px",
            borderRadius: "4px",
            border: "1px solid #ccc",
            outline: "none",
          }}
        />

        <label
          style={{ marginBottom: "8px", fontWeight: "500" }}
          htmlFor="delay"
        >
          Delay (ms)
        </label>
        <input
          type="number"
          id="delay"
          value={delay}
          onChange={(e) => setDelay(e.target.value)}
          required
          style={{
            width: "100%",
            padding: "8px",
            marginBottom: "16px",
            borderRadius: "4px",
            border: "1px solid #ccc",
            outline: "none",
          }}
        />

        <button
          type="submit"
          disabled={isProcessing}
          style={{
            padding: "8px 16px",
            color: "white",
            borderRadius: "4px",
            transition: "background-color 0.3s",
            backgroundColor: isProcessing ? "#b0bec5" : "#2196F3",
            cursor: isProcessing ? "not-allowed" : "pointer",
          }}
        >
          {isProcessing ? "Capturing..." : "Capture Screenshot"}
        </button>
      </form>

      {/* Example HTML Element to Capture */}
      <div id="capture-area" style={{ display: "none" }}>
        <h3
          style={{
            fontSize: "20px",
            fontWeight: "600",
          }}
        >
          Content to Capture
        </h3>
        <p>This is an example of the HTML content that will be captured.</p>
      </div>
    </div>
  );
}
Nach dem Login kopieren

Fazit

Dieses Tutorial behandelt die Einrichtung eines Webseiten-Erfassungstools in Next.js, die Handhabung von Screenshots mit Puppeteer und die Erstellung einer interaktiven Frontend-Komponente. Denken Sie daran, Puppeteer lokal zu verwenden und in der Produktion auf Puppeteer-Core umzusteigen, um die Bundle-Größe zu reduzieren und für serverlose Umgebungen zu optimieren. Viel Spaß beim Codieren!

Das obige ist der detaillierte Inhalt vonSo erfassen Sie Webseiten-Screenshots mit Next.js und Puppeteer. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

AI Hentai Generator

AI Hentai Generator

Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

R.E.P.O. Energiekristalle erklärten und was sie tun (gelber Kristall)
2 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
Repo: Wie man Teamkollegen wiederbelebt
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Abenteuer: Wie man riesige Samen bekommt
3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Ersetzen Sie Stringzeichen in JavaScript Ersetzen Sie Stringzeichen in JavaScript Mar 11, 2025 am 12:07 AM

Ersetzen Sie Stringzeichen in JavaScript

JQuery überprüfen, ob das Datum gültig ist JQuery überprüfen, ob das Datum gültig ist Mar 01, 2025 am 08:51 AM

JQuery überprüfen, ob das Datum gültig ist

JQuery Get Element Polsterung/Rand JQuery Get Element Polsterung/Rand Mar 01, 2025 am 08:53 AM

JQuery Get Element Polsterung/Rand

10 JQuery Accords Registerkarten 10 JQuery Accords Registerkarten Mar 01, 2025 am 01:34 AM

10 JQuery Accords Registerkarten

10 lohnt 10 lohnt Mar 01, 2025 am 01:29 AM

10 lohnt

HTTP-Debugging mit Knoten und HTTP-Konsole HTTP-Debugging mit Knoten und HTTP-Konsole Mar 01, 2025 am 01:37 AM

HTTP-Debugging mit Knoten und HTTP-Konsole

Benutzerdefinierte Google -Search -API -Setup -Tutorial Benutzerdefinierte Google -Search -API -Setup -Tutorial Mar 04, 2025 am 01:06 AM

Benutzerdefinierte Google -Search -API -Setup -Tutorial

JQuery fügen Sie Scrollbar zu Div hinzu JQuery fügen Sie Scrollbar zu Div hinzu Mar 01, 2025 am 01:30 AM

JQuery fügen Sie Scrollbar zu Div hinzu

See all articles