gtm
phone-call +336 67 57 33 79

Services, conseils et formations en Web Scraping

Télécharger et retoucher une image en JavaScript / Node avec la librairie Jimp

Dans le cadre d'un scraping, il peut vous arriver d'avoir le besoin de télécharger des images présentes sur le site que vous visez. C'est précisément la demande qui m'a été faite, dans le cadre d'une mission. Mais plus que simplement télécharger les images en question, il fallait que je sois en mesure d'appliquer des retouches dessus. La librairie Jimp permet justement de faire les deux.

Pour illustrer le fonctionnement de Jimp, partons d'un cas concret. Nombreuses sont les personnes souhaitant récupérer des informations sur des sites d'annonces tels que Le Bon Coin. Admettons que vous souhaitiez, dans le cadre de votre script de scraping, récupérer également l'image principale de l'annonce.

node_scraping_jimp

Nous prenons ici une annonce au hasard.

let img_url = $('._2x8BQ > img').attr('src');

Notre but n'est pas ici de montrer l'ensemble du script de scraping. Ci-dessus, voici simplement la ligne permettant de récupérer l'url de l'image principale de l'annonce. A partir du moment où nous avons cette information, comment opérer ensuite ?

C'est à ce moment qu'intervient Jimp. Nous allons tout d'abord installer la librairie via NPM en nous placant dans le répertoire où se trouve notre script de scraping, puis en tapant la commande suivante dans la console Node :

Npm i –save Jimp

On rajoute ensuite bien évidemment un fameux « require » en haut du fichier de scraping, afin de charger la librairie.

Let Jimp = require('Jimp');

On va donc maintenant pouvoir passer à l'action. Jimp s'utilise de façon simple et compréhensible. Pour une utilisation basique, il faut partir de la méthode Jimp.read, dans laquelle on passe l'url de l'image, et qui va ensuite s'occuper d'effectuer les traitements demandés, avant de retourner une Promesse :

Jimp.read('http://www.leboncoin.com/chemin/vers/image.jpg')
  .then(image => {
    // Vous faites ici vos manipulations sur l'image.
  })
  .catch(err => {
    // Vous récupérez ici une exception en cas d'erreur.
  });
								


Voila le principe !

Voyons ce que cela donne de façon plus concrète. Imaginons que nous souhaitions redimensionner les images que l'on récupère dans le cadre de notre scraping, afin qu'elle soit toutes aux dimensions suivantes : 500px / 350px. Notre code va ainsi ressembler à ça.

Jimp.read(img_url)
  .then(function(img) {
    return img
      .resize(500, 350)
      .quality(90)
      .write('./leboncoin_image.jpg'); 
  })
  .catch(err => {
    console.error(err);
  }); 
								

On utilise donc la méthode resize(). Sur la ligne suivante, la méthode quality() permet de définir le niveau de qualité du JPEG enregistré (sur une échelle de 0 à 100). Et enfin, sur la ligne suivante, on utilise la méthode write() pour indiquer que l'on souhaite enregistrer l'image en local, en indiquant le path approprié. Et oui, Jimp nous donne la possibilité de faire toutes ces choses en seulement quelques lignes !

Admettons maintenant que nous souhaitions effectuer un redimensionnement mais à partir d'un pourcentage. Nous allons cette fois-ci utiliser la méthode scale() :


Jimp.read(img_url)
  .then(function(img) {
    return img
      .scale(0.5)
      .write('./leboncoin_image.jpg'); 
  })
  .catch(err => {
    console.error(err);
  }); 

								

On aura ici une image redimensionnée à 50% de sa taille initiale.

Vous souhaitez passer l'image en noir et blanc ? Avec l'utilisation de la méthode greyScale(), vous obtiendrez le résultat suivant :

node_scraping_jimp

Admettons désormais que vous souhaitiez vous débarrasser de la mention « leboncoin » en bas à droite de l'image ? Pour cela il va falloir utiliser la méthode crop(). Voici les paramètres qu'elle prend en arguments :


Crop(x, y, width, height) ;

								

Le premier argument indique le point de départ de notre sélection, sur le plan horizontal.
Le second argument indique le point de départ de notre sélection, sur le plan vertical.
Les deux derniers arguments indiquent la largeur et la hauteur du périmètre de sélection. Au final, tous ces arguments permettent de tracer la zone que l'on souhaite garder sur l'image, comme on le verrait avec un logiciel de retouches basique. Tout ce qui se trouve en dehors sera rogné.
Dans notre cas, vu que les images présentes sur Le Bon Coin n'ont pas toutes les mêmes dimensions, il va falloir que nous nous adaptions à chaque fois à la taille de l'image en question. Nous allons donc récupérer la hauteur de l'image, afin de pouvoir supprimer la zone qui nous gène, en bas de l'image.


Jimp.read(img_url)
  .then(function(img) {
    return img
      .crop(0, 0, img.bitmap.width, img.bitmap.height - 30)
      .write('./LBC_pics/'+img_id); // save
  }, img_id)
  .catch(err => {
    console.error(err);
  });       
								

Et le résultat:

node_scraping_jimp

On a donc la même image que celle présente sur le site, sauf que l'on a rogné 30 pixels en bas.

Pour que vous compreniez bien l'influence des différents paramètres de la méthode crop(), si on change les arguments pour mettre les suivants :


crop(50, 50, 200, 300) 
								

Vous obtiendrez cette image:

node_scraping_jimp

Jimp propose de nombreuses méthodes différentes dont voici la liste ici :


/* Resize */
image.contain( w, h[, alignBits || mode, mode] );    // scale the image to the given width and height, some parts of the image may be letter boxed
image.cover( w, h[, alignBits || mode, mode] );      // scale the image to the given width and height, some parts of the image may be clipped
image.resize( w, h[, mode] );     // resize the image. Jimp.AUTO can be passed as one of the values.
image.scale( f[, mode] );         // scale the image by the factor f
image.scaleToFit( w, h[, mode] ); // scale the image to the largest size that fits inside the given width and height
 
// An optional resize mode can be passed with all resize methods.
 
/* Crop */
image.autocrop([tolerance, frames]); // automatically crop same-color borders from image (if any), frames must be a Boolean
image.autocrop(options);          // automatically crop same-color borders from image (if any), options may contain tolerance, cropOnlyFrames, cropSymmetric, leaveBorder
image.crop( x, y, w, h );         // crop to the given region
 
/* Composing */
image.blit( src, x, y, [srcx, srcy, srcw, srch] );
                                  // blit the image with another Jimp image at x, y, optionally cropped.
image.composite( src, x, y, [{ mode, opacitySource, opacityDest }] );     // composites another Jimp image over this image at x, y
image.mask( src, x, y );          // masks the image with another Jimp image at x, y using average pixel value
image.convolute( kernel );        // applies a convolution kernel matrix to the image or a region
 
/* Flip and rotate */
image.flip( horz, vert );         // flip the image horizontally or vertically
image.mirror( horz, vert );       // an alias for flip
image.rotate( deg[, mode] );      // rotate the image clockwise by a number of degrees. Optionally, a resize mode can be passed. If `false` is passed as the second parameter, the image width and height will not be resized.
 
/* Colour */
image.brightness( val );          // adjust the brighness by a value -1 to +1
image.contrast( val );            // adjust the contrast by a value -1 to +1
image.dither565();                // ordered dithering of the image and reduce color space to 16-bits (RGB565)
image.greyscale();                // remove colour from the image
image.invert();                   // invert the image colours
image.normalize();                // normalize the channels in an image
 
/* Alpha channel */
image.hasAlpha();                     // determines if an image contains opaque pixels
image.fade( f );                  // an alternative to opacity, fades the image by a factor 0 - 1. 0 will haven no effect. 1 will turn the image
image.opacity( f );               // multiply the alpha channel by each pixel by the factor f, 0 - 1
image.opaque();                   // set the alpha channel on every pixel to fully opaque
image.background( hex );          // set the default new pixel colour (e.g. 0xFFFFFFFF or 0x00000000) for by some operations (e.g. image.contain and
 
/* Blurs */
image.gaussian( r );              // Gaussian blur the image by r pixels (VERY slow)
image.blur( r );                  // fast blur the image by r pixels
 
/* Effects */
image.posterize( n );             // apply a posterization effect with n level
image.sepia();                    // apply a sepia wash to the image
image.pixelate( size[, x, y, w, h ]);  // apply a pixelation effect to the image or a region
 
/* 3D */
image.displace( map, offset );    // displaces the image pixels based on the provided displacement map. Useful for making stereoscopic 3D images.

								

Cette liste est extraite de la page de documentation NPM du package. Je vous invite à vous y rendre pour plus d'informations : https://www.npmjs.com/package/jimp

Vous souhaitez bénéficier d'une formation présentielle en web scraping ? Vous pouvez probablement vous faire financer une de nos formations ! Pour en savoir plus téléchargez le programme de nos formations physiques.