نحوه گرفتن اسکرین شات از صفحه وب با Next.js و Puppeteer

Summarize this content to 400 words in Persian Lang
گرفتن اسکرین شات از صفحات وب به صورت برنامه ای می تواند برای تولید پیش نمایش، ایجاد گزارش های مبتنی بر تصویر و موارد دیگر بسیار مفید باشد. در این راهنما، ما یک مسیر API Next.js خواهیم ساخت که یک URL را می گیرد و یک اسکرین شات PNG ایجاد می کند. راهاندازی ما از Puppeteer و chrome-aws-lambda برای استفاده از مرورگر بدون هد Chrome استفاده میکند و آن را همهکاره و آماده تولید میکند.
ما با راهاندازی یک پروژه Next.js و قدم به قدم کدها را شروع میکنیم تا بفهمیم که API چگونه اسکرینشاتها را میگیرد.
پیش نیازها
راه اندازی برنامه Next.js
پیکربندی مسیر API با Puppeteer
ایجاد کامپوننت React برای رابط کپچر
توضیح تنظیمات محلی در مقابل استقرار برای Puppeteer
شروع کار با یک پروژه Next.js جدید
یک برنامه Next.js جدید ایجاد کنید:
npx create-next-app@latest capture-image-app
cd capture-image-app
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
وابستگی های لازم را نصب کنید:
npm install puppeteer puppeteer-core chrome-aws-lambda busboy
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
مرحله 2: مسیر API را برای ایجاد اسکرین شات ایجاد کنید
اکنون، یک نقطه پایانی API برای گرفتن و برگرداندن اسکرین شات ها بر اساس URL ارائه شده، تنظیم می کنیم.
در pages/api پوشه، یک فایل جدید به نام ایجاد کنید generate-png.ts و این کد را اضافه کنید:
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 => new Promise((resolve) => setTimeout(resolve, ms));
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
): Promise {
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”);
}
}
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
*توضیح: انتخاب عروسک گردان برای محیط های محلی در مقابل تولید*در این کد، یک Import پویا برای Puppeteer تنظیم کرده ایم:
توسعه محلی: اگر NODE_ENV نیست production، استفاده می کند puppeteer، که راه اندازی آن ساده تر است و نیازی ندارد chrome-aws-lambda.
تولید: برای استقرارهای بدون سرور، محیط شناسایی خواهد کرد NODE_ENV به عنوان production و Puppeteer-core همراه با chrome-aws-lambda، که به آن اجازه می دهد در AWS Lambda و سایر محیط های مشابه کار کند. در این تنظیمات، chrome-aws-lambda مسیر صحیح Chromium را فراهم می کند و از سازگاری با ارائه دهندگان بدون سرور اطمینان می دهد.
مرحله 3: یک کامپوننت Simple React برای رابط کاربری ایجاد کنید
در اینجا، یک فرم ساده ایجاد میکنیم که به کاربران اجازه میدهد مقادیر ورودی صفحه وب را ثبت کنند. این فرم تابع تولید را برای گرفتن و دانلود اسکرین شات در قالب PDF فعال می کند.
import { useState } from “react”;
export default function ScreenCaptureComponent() {
const [isProcessing, setProcessing] = useState(false);
const [width, setWidth] = useState(“1920”);
const [height, setHeight] = useState(“1000”);
const [delay, setDelay] = useState(“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 (
Webpage Screenshot Capture
{
e.preventDefault();
generateCapture();
}}
style={{
display: “flex”,
flexDirection: “column”,
alignItems: “center”,
marginBottom: “16px”,
}}
>
Width (px)
setWidth(e.target.value)}
style={{
width: “100%”,
padding: “8px”,
marginBottom: “16px”,
borderRadius: “4px”,
border: “1px solid #ccc”,
outline: “none”,
}}
>
1920 (Full HD)
1366 (Laptop)
1280 (Desktop)
1024 (Tablet Landscape)
768 (Tablet Portrait)
375 (Mobile)
Height (px)
setHeight(e.target.value)}
required
style={{
width: “100%”,
padding: “8px”,
marginBottom: “16px”,
borderRadius: “4px”,
border: “1px solid #ccc”,
outline: “none”,
}}
/>
Delay (ms)
setDelay(e.target.value)}
required
style={{
width: “100%”,
padding: “8px”,
marginBottom: “16px”,
borderRadius: “4px”,
border: “1px solid #ccc”,
outline: “none”,
}}
/>
{isProcessing ? “Capturing…” : “Capture Screenshot”}
{/* Example HTML Element to Capture */}
Content to Capture
This is an example of the HTML content that will be captured.
);
}
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
نتیجه گیری
این آموزش راه اندازی یک ابزار ضبط صفحه وب در Next.js، مدیریت اسکرین شات ها را پوشش می دهد Puppeteer، و ایجاد یک مؤلفه frontend تعاملی. به یاد داشته باشید استفاده کنید puppeteer به صورت محلی و تغییر به puppeteer-core در تولید برای کاهش اندازه باندل و بهینه سازی برای محیط های بدون سرور. کد نویسی مبارک!
گرفتن اسکرین شات از صفحات وب به صورت برنامه ای می تواند برای تولید پیش نمایش، ایجاد گزارش های مبتنی بر تصویر و موارد دیگر بسیار مفید باشد. در این راهنما، ما یک مسیر API Next.js خواهیم ساخت که یک URL را می گیرد و یک اسکرین شات PNG ایجاد می کند. راهاندازی ما از Puppeteer و chrome-aws-lambda برای استفاده از مرورگر بدون هد Chrome استفاده میکند و آن را همهکاره و آماده تولید میکند.
ما با راهاندازی یک پروژه Next.js و قدم به قدم کدها را شروع میکنیم تا بفهمیم که API چگونه اسکرینشاتها را میگیرد.
پیش نیازها
- راه اندازی برنامه Next.js
- پیکربندی مسیر API با Puppeteer
- ایجاد کامپوننت React برای رابط کپچر
- توضیح تنظیمات محلی در مقابل استقرار برای Puppeteer
شروع کار با یک پروژه Next.js جدید
- یک برنامه Next.js جدید ایجاد کنید:
npx create-next-app@latest capture-image-app
cd capture-image-app
- وابستگی های لازم را نصب کنید:
npm install puppeteer puppeteer-core chrome-aws-lambda busboy
مرحله 2: مسیر API را برای ایجاد اسکرین شات ایجاد کنید
اکنون، یک نقطه پایانی API برای گرفتن و برگرداندن اسکرین شات ها بر اساس URL ارائه شده، تنظیم می کنیم.
در pages/api
پوشه، یک فایل جدید به نام ایجاد کنید generate-png.ts
و این کد را اضافه کنید:
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 => new Promise((resolve) => setTimeout(resolve, ms));
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
): Promise {
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");
}
}
*توضیح: انتخاب عروسک گردان برای محیط های محلی در مقابل تولید
*
در این کد، یک Import پویا برای Puppeteer تنظیم کرده ایم:
-
توسعه محلی: اگر
NODE_ENV
نیستproduction
، استفاده می کندpuppeteer
، که راه اندازی آن ساده تر است و نیازی نداردchrome-aws-lambda
. -
تولید: برای استقرارهای بدون سرور، محیط شناسایی خواهد کرد
NODE_ENV
به عنوانproduction
و Puppeteer-core همراه با chrome-aws-lambda
، که به آن اجازه می دهد در AWS Lambda و سایر محیط های مشابه کار کند. در این تنظیمات،chrome-aws-lambda
مسیر صحیح Chromium را فراهم می کند و از سازگاری با ارائه دهندگان بدون سرور اطمینان می دهد.
مرحله 3: یک کامپوننت Simple React برای رابط کاربری ایجاد کنید
در اینجا، یک فرم ساده ایجاد میکنیم که به کاربران اجازه میدهد مقادیر ورودی صفحه وب را ثبت کنند. این فرم تابع تولید را برای گرفتن و دانلود اسکرین شات در قالب PDF فعال می کند.
import { useState } from "react";
export default function ScreenCaptureComponent() {
const [isProcessing, setProcessing] = useState(false);
const [width, setWidth] = useState("1920");
const [height, setHeight] = useState("1000");
const [delay, setDelay] = useState("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 (
);
}
نتیجه گیری
این آموزش راه اندازی یک ابزار ضبط صفحه وب در Next.js، مدیریت اسکرین شات ها را پوشش می دهد Puppeteer
، و ایجاد یک مؤلفه frontend تعاملی. به یاد داشته باشید استفاده کنید puppeteer
به صورت محلی و تغییر به puppeteer-core
در تولید برای کاهش اندازه باندل و بهینه سازی برای محیط های بدون سرور. کد نویسی مبارک!