Node.js: usare Puppeteer per creare screenshot dei siti web su desktop e server Linux

Node.js: usare Puppeteer per creare screenshot dei siti web su desktop e server Linux

In questo tutorial vedremo come utilizzare Puppeteer in Node.js per creare screenshot di pagine web sia su desktop che su server Linux.

L'aspetto fondamentale da capire è che Puppeteer non fa altro che fornire delle API con cui creare e gestire un'istanza di un browser che viene installato localmente.

Su desktop non sono richiesti particolari accorgimenti, mentre su server Linux vanno prima installate le dipendenze necessarie per poter permettere al browser di operare.

Quindi come prima cosa su server Linux dobbiamo installare tali dipendenze.

# Debian/Ubuntu

sudo apt-get update

sudo apt-get install -y gconf-service libasound2 libatk1.0-0 libatk-bridge2.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget

sudo apt-get install -y libgbm-dev

Un'altra differenza tra desktop e server Linux sta nella creazione dell'istanza del browser tramite le API di Puppeteer. Su server Linux il metodo launch() va invocato nel modo seguente:

const browser = await puppeteer.launch({args: ['--no-sandbox']});

Quello che vogliamo implementare è un endpoint di un'API che crei uno screenshot a partire dall'URL e dalle dimensioni passate dal client con una richiesta POST e restituisca l'URL di dati dello screenshot creato.

Possiamo quindi creare la seguente classe:

'use strict';

const puppeteer = require('puppeteer');
const validator = require('validator');

class Preview {
    constructor(url, width, height) {
        this.url = url;
        this.width = width;
        this.height = height;
    }

    validate() {
        if (!validator.isURL(this.url)) {
            return false;
        }
        if (this.width < 300 || this.width > 2560) {
            return false;
        }
        if (this.height < 500 || this.height > 1700) {
            return false;
        }
        return true;
    }

    async create() {
        if (!this.validate()) {
            return Promise.reject();
        }
        try {
            const browser = await puppeteer.launch();
            // Server: puppeteer.launch({args: ['--no-sandbox']});
            const page = await browser.newPage();
            await page.setViewport({
                width: this.width,
                height: this.height,
                deviceScaleFactor: 1
            });
            await page.goto(this.url);
            const data = await page.screenshot({encoding: 'base64'});
            await browser.close();
            return `data:image/png;base64,${data}`;

        } catch (err) {
            console.log(err);
            return Promise.reject(err);
        }
    }
}

module.exports = Preview;

Il nostro endpoint sarà quindi:

'use strict';

const express = require('express');
const router = express.Router();
const Preview = require('../classes/Preview');

router.post('/screenshot', async (req, res, next) => {
    let url = '', width = 0, height = 0;
    if(req.body.url && req.body.width && req.body.height) {
        url = req.body.url;
        width = req.body.width;
        height = req.body.height;
    }
    const preview = new Preview(url, width, height);
    try {
        const image = await preview.create();
        res.send({ image });
    } catch(error) {
        res.send({ error  });
    }
});

Come si può notare, una volta risolto il passaggio delle dipendenze sul server, la procedura effettiva è relativamente semplice.

Torna su