node.js - 从 puppeteer 截图中保存图像数据的推荐方法是什么?

标签 node.js mongodb puppeteer

我正在制作一个应用程序,用于在 map 上绘制运行路线并将它们保存到 mongodb 数据库中。

目前,我正在使用 puppeteer 访问我的应用程序中的路线,并将坐标作为查询字符串传递给 map 组件。加载 map 后,我截取屏幕截图,将返回的 Buffer 转换为 base64 编码的字符串,将其保存到数据库中,并使用该字符串在前端显示图像。

整个过程的中间件是这样的:

exports.screenshotMap = async (req, res, next) => {
  try {
    const { lineFeatures } = req.body;
    const browser = await puppeteer.launch({
      args: ['--no-sandbox', '--disable-setuid-sandbox'],
    });

    // open new browser
    const page = await browser.newPage();

    // create array of coordinates from geojson features
    const coords = lineFeatures.map(line => line.geometry.coordinates);
    // reduce to 2D array of [lat, lon] coords
    const flattenedCoords = coords.reduce((accum, arr) => {
      return accum.concat(arr);
    }, []);
    // Stringify coords before using them as query string
    const coordsStr = JSON.stringify(flattenedCoords);

    // goto page with map sending coordintaes along
    await page.goto(`http://localhost:3000/test?coords=${coordsStr}`, {
      waitUntil: 'networkidle0',
    });

    // wait for map to load, call onLoad callback, and set state to make the h1 visible
   await page.waitForSelector('h1');
    // wait one more second to make sure all tiles for the map are loaded. Longer routes can require significantly more tiles
    await page.waitFor(1000);

    const image = await page.screenshot({
      type: 'jpeg',
      quality: 100,
      clip: {
        x: 0,
        y: 70,
        width: 640,
        height: 360,
      },
      omitBackground: true,
    });

    await browser.close();
    // convert buffer to base64 string
    const base64Image = await image.toString('base64');
    // attach to request object to be used in the next middleware
    req.image = base64Image;
    next();

  } catch (err) {
    res.status(400).send(err);
  }
};

这种方法有效,但是我想知道是否有更好的方法。我已经阅读了存储 Buffer 数据更适合数据库内存用途,因为 base64 字符串很长。更好的方法是保存缓冲区数据并将其转换为编码字符串,然后再将其发送回客户端?是否有处理此类数据的推荐方法?我有兴趣听取其他人的想法和方法。

最佳答案

我想出的解决方案是将从屏幕截图返回的缓冲区保存到 S3 存储桶,然后将唯一标识符 url 存储到我的数据库中。

这是屏幕截图的中间件:

import puppeteer from 'puppeteer';
//import chromium from 'chrome-aws-lambda';

const takeMapImage = handler => async (req, res) => {
  try {
    const { lines } = req.body;

    // should work for most node projects
    const browser = await puppeteer.launch({
       args: ['--no-sandbox', '--disable-setuid-sandbox'],
    });

    // if youre using lambda functions
    // const browser = await chromium.puppeteer.launch({
    //  executablePath: await chromium.executablePath,
    // args: chromium.args,
    // defaultViewport: chromium.defaultViewport,
    // headless: chromium.headless,
    // });

    // open new browser
    const page = await browser.newPage();

    const url = 'https://yourwebstieurl.com';

    await page.goto(
      `${url}`,
      {
        waitUntil: 'networkidle0',
      }
    );

    // provide some waiting time if needed
    await page.waitFor(1000);

   // image buffer returned from screenshot
    const imageBuffer = await page.screenshot({
      type: 'jpeg',
      quality: 100,
      clip: {
        x: 0,
        y: 0,
        width: 640,
        height: 360,
      },
      omitBackground: true,
    });


    // attach to request object to be used in the next middleware
    req.buffer = imageBuffer;

    next();

  } catch (err) {
    console.log(err);
    return res
      .status(422)
      .send({ message: 'there was an error taking picture' });
  }
};

然后是将图像保存到 s3 的中间件。您将需要创建一个存储桶并获取凭据:
import AWS from 'aws-sdk';
import uuid from 'uuid/v1';

// create your s3instance with your credentials
const s3 = new AWS.S3({
  accessKeyId: process.env.S3_ACCESS_KEY_ID,
  secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
});

const saveImageToS3 = handler => async (req, res) => {
  try {
    // use user id as identifier in S3 bucket
    const { id } = req.user;
    const { buffer } = req;

    // s3 file name
    const key = `${id}/${uuid()}.jpeg`;

    const params = {
      Bucket: 'your-bucket-name',
      Key: key,
      Body: buffer,
      ContentEncoding: 'base64',
      ContentType: 'image/jpeg',
    };

    // upload to bucket
    const response = await s3.upload(params).promise();
    // pass url to next middleware to save to db
    req.image = response.Location;
    next();
  } catch (e) {
    console.log(e);
    return res.status(422).json({ message: 'user error saving image to s3' });
  }
};

关于node.js - 从 puppeteer 截图中保存图像数据的推荐方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56693877/

相关文章:

node.js - 构建 Restful API 时选择哪种 HTTP 方法

node.js - 如何从 Node 脚本运行 gulp 任务

Mongodb聚合框架: Does $group use index?

javascript - Puppeteer Bright Data 代理返回 ERR_NO_SUPPORTED_PROXY 或 CERT 错误

javascript - Node.js 中数组和对象的混淆

node.js - 如何在node js中使用serialport正确读取?

java - 在 MongoDB 中添加多个子文档

java - MongoDB Java 驱动程序的自定义实现

javascript - 如何在 puppeteer 中执行 JavaScript 代码

chromium - puppeteer 不会打开没有协议(protocol)的 url