免费截图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. 运行应用
- 启动应用:命令 node screenshot.js
- 访问
http://localhost:3000/screenshot
进行测
我们通过 Puppeteer 和 Express 实现了一个简单的网页截图 API。我们使用 Puppeteer 来抓取网页,并利用 Sharp 对截图进行裁剪和调整大小。通过 HTTP GET 请求,用户可以传递 URL、截图的宽高以及格式,API 会返回截图结果。
这个接口可以扩展,例如加入更多的功能(如添加延时、模拟用户行为等),使得它在实际项目中更加灵活和实用。
8. 后续扩展
- 支持截图区域:可以允许用户指定截图页面的某个区域而不是整个页面。
- 增加延时控制:在截图之前,增加页面加载时间,以确保页面元素完全加载。
- 优化性能:通过对截图进行缓存,减少对相同页面的重复请求处理。