使用 Puppeteer 实现网页截图 API 部署教程

免费截图API通道:

在现代的 Web 开发中,网页截图是一项常见需求,尤其是当你需要捕获网页内容并将其作为图像保存或分享时。通过 Puppeteer,我们可以很容易地实现网页截图的自动化,甚至可以将这一功能封装为 API 接口,供用户通过 HTTP 请求来获取网页截图。

下面将介绍如何使用 Puppeteer 来创建一个网页截图 API,并将其部署为一个可供访问的服务。这个 API 会接受用户的请求,自动抓取网页并返回截图,支持多种自定义选项,例如设置截图的宽度和高度。

Puppeteer是什么?

Puppeteer 是一个 Node.js 库,用于控制无头 Chromium 浏览器,支持浏览器自动化任务。Puppeteer 可以执行浏览器的几乎所有操作,比如模拟点击、表单提交、网页截图等。它的最大优势是能够进行无头浏览,即不需要显示浏览器界面,能够在后台快速完成任务。

2. 环境准备

在开始之前,请确保你已经安装了 Node.js。可以通过 Node.js 官网 下载和安装。

3. 项目初始化

npm init -y

安装必要的依赖:

npm install puppeteer express sharp

PS:sharp非必须包,主要是处理图片的,如果你有一定的开发能,使用镜像储存,就不需要这个依赖包,对于图片的压缩,像素裁剪可以直接通过镜像储存的多媒体样式来实现

  • puppeteer: 用于抓取网页并生成截图。
  • express: 用于构建 HTTP 服务器。
  • sharp: 用于对截图进行裁剪和压缩。

4. 编写网页截图 API 代码

接下来,我们编写一个简单的 Express 应用,接收用户请求,使用 Puppeteer 抓取网页并生成截图,最后返回给用户。

创建 screenshot.js 文件,代码如下:

// 简单的demo 你可以自己的需求来具体实现功能
const express = require('express');
const puppeteer = require('puppeteer');
const sharp = require('sharp');
const path = require('path');
const fs = require('fs');
const urlModule = require('url');

const app = express();

// 确保截图目录存在
const screenshotDir = path.join(__dirname, 'screenshots');
if (!fs.existsSync(screenshotDir)) {
  fs.mkdirSync(screenshotDir);
}

// 截图接口
app.get('/screenshot', async (req, res) => {
  const { url, width, height, format = 'png', quality = 80 } = req.query;

  // 验证必选参数 url, width, height
  if (!url || !width || !height) {
    return res.status(400).json({ error: 'Missing required parameters (url, width, height).' });
  }

  // 转义 URL 特殊字符,避免在文件名中出错
  const targetUrl = urlModule.format(urlModule.parse(url));
  const fileName = targetUrl.replace(/[^a-zA-Z0-9]/g, (match) => match === ':' ? '#' : match === '/' ? '@' : match) + '.' + format;
  const screenshotPath = path.join(screenshotDir, fileName);
  const tempScreenshotPath = path.join(screenshotDir, 'temp_' + fileName); // 临时文件路径

  try {
    // 启动 Puppeteer 浏览器
    const browser = await puppeteer.launch();
    const page = await browser.newPage();

    // 获取页面的实际宽高
    const pageWidth = 1920;  // 假设的浏览器窗口默认宽度
    const pageHeight = 1080; // 假设的浏览器窗口默认高度

    // 用户请求的宽高
    const requestedWidth = parseInt(width);
    const requestedHeight = parseInt(height);

    // 计算原始页面比例
    const pageRatio = pageWidth / pageHeight;
    const requestedRatio = requestedWidth / requestedHeight;

    let targetWidth = requestedWidth;
    let targetHeight = requestedHeight;

    // 等比缩放:如果请求的比例大于页面的比例,调整高度;否则调整宽度
    if (requestedRatio > pageRatio) {
      targetHeight = Math.round(requestedWidth / pageRatio);  // 根据原始比例调整高度
    } else if (requestedRatio < pageRatio) {
      targetWidth = Math.round(requestedHeight * pageRatio); // 根据原始比例调整宽度
    }

    // 设置浏览器视口大小
    await page.setViewport({
      width: targetWidth,
      height: targetHeight,
      deviceScaleFactor: 1, // 避免高DPI设备造成像素密度变化
    });

    // 打开目标页面
    await page.goto(targetUrl, { waitUntil: 'networkidle2' });

    // 截取页面截图并保存到临时文件
    await page.screenshot({
      path: tempScreenshotPath,
      type: format,
      quality: format === 'jpeg' ? parseInt(quality) : undefined,
      fullPage: true, // 截取整个页面
    });

    // 获取图片的实际尺寸
    const image = sharp(tempScreenshotPath);
    const metadata = await image.metadata();

    // 计算裁剪区域的 left 和 top 确保不会超出图片边界
    const left = Math.floor((metadata.width - requestedWidth) / 2);
    const top = Math.floor((metadata.height - requestedHeight) / 2);

    // 如果裁剪区域超出图片尺寸,限制裁剪区域
    const extractWidth = Math.min(requestedWidth, metadata.width - left);
    const extractHeight = Math.min(requestedHeight, metadata.height - top);

    // 使用 sharp 进行居中裁剪并调整大小
    await image
      .extract({ left, top, width: extractWidth, height: extractHeight })
      .resize(requestedWidth, requestedHeight) // 确保最终尺寸符合请求的尺寸
      .toFile(screenshotPath); // 输出到目标路径

    // 删除临时文件
    fs.unlinkSync(tempScreenshotPath);

    // 关闭浏览器
    await browser.close();

    // 返回截图文件
    res.sendFile(screenshotPath, { root: __dirname }, (err) => {
      if (err) {
        res.status(500).json({ error: 'Failed to send screenshot.' });
      }
    });
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: 'Failed to take screenshot.' });
  }
});

// 启动服务器
const port = 3000;
app.listen(port, () => {
  console.log(`Server is running on http://localhost:${port}`);
});

5. 接口说明

  • GET /screenshot: 接受以下查询参数,返回网页截图。
    • url (必填): 需要截图的目标网页 URL。
    • width (必填): 截图宽度。
    • height (必填): 截图高度。
    • format (可选): 输出图片格式,默认为 png,支持 jpeg 格式。
    • quality (可选): 当格式为 jpeg 时,可以设置压缩质量,默认为 80

例如,您可以通过以下 URL 请求截图:

http://localhost:3000/screenshot?url=https://www.baidu.com&width=600&height=400

6. 运行应用

  1. 启动应用:命令  node screenshot.js
  2. 访问 http://localhost:3000/screenshot 进行测

我们通过 Puppeteer 和 Express 实现了一个简单的网页截图 API。我们使用 Puppeteer 来抓取网页,并利用 Sharp 对截图进行裁剪和调整大小。通过 HTTP GET 请求,用户可以传递 URL、截图的宽高以及格式,API 会返回截图结果。

这个接口可以扩展,例如加入更多的功能(如添加延时、模拟用户行为等),使得它在实际项目中更加灵活和实用。

8. 后续扩展

  • 支持截图区域:可以允许用户指定截图页面的某个区域而不是整个页面。
  • 增加延时控制:在截图之前,增加页面加载时间,以确保页面元素完全加载。
  • 优化性能:通过对截图进行缓存,减少对相同页面的重复请求处理。
© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...