Retour au blog
Guides
Robert SfichiLast updated on Apr 28, 202616 min read

Web Scraping avec JavaScript et Node.Js

Web Scraping avec JavaScript et Node.Js

Soyons honnêtes. À partir de maintenant, le volume de données sur Internet ne fera que croître. On ne peut vraiment rien y faire. C'est là que les outils de scraping entrent en jeu.

Dans l'article suivant, nous allons vous montrer comment créer votre propre scraper Web en utilisant JavaScript comme langage de programmation principal.

Comprendre le web scraping avec JavaScript

Un web scraper est un logiciel qui vous aide à automatiser le processus fastidieux de collecte de données utiles sur des sites web tiers. En général, cette procédure consiste à envoyer une requête à une page web spécifique, à lire le code HTML et à analyser ce code pour extraire certaines données.

Pourquoi scraper des données ?

Imaginons que vous souhaitiez créer une plateforme de comparaison de prix. Vous avez besoin des prix de plusieurs articles provenant de quelques boutiques en ligne. Un outil de web scraping peut vous aider à gérer cela en quelques minutes.

Peut-être cherchez-vous à obtenir de nouveaux prospects pour votre entreprise, ou même à trouver les meilleurs prix pour des vols ou des hôtels. Alors que nous parcourions le Web pour faire des recherches en vue de cet article, nous sommes tombés sur Brisk Voyage.

Brisk Voyage est une application web qui aide ses utilisateurs à trouver des escapades de week-end pas chères de dernière minute. Grâce à une technologie de web scraping, ils parviennent à vérifier en permanence les prix des vols et des hôtels. Lorsque le web scraper trouve un voyage à un prix exceptionnellement bas, l'utilisateur reçoit un e-mail contenant les instructions de réservation.

À quoi servent les web scrapers ?

Les développeurs utilisent les web scrapers pour toutes sortes de récupération de données, mais les cas d'utilisation les plus courants sont les suivants :

  • Analyse de marché
  • Comparaison des prix
  • Génération de prospects
  • Recherche universitaire
  • Collecte d'ensembles de données d'entraînement et de test pour l'apprentissage automatique

Quels sont les défis du web scraping avec JavaScript et Node.js ?

Vous connaissez ces petites cases à cocher qui vous obligent à confirmer que vous n'êtes pas un robot ? Eh bien, elles ne parviennent pas toujours à tenir les robots à distance.

Mais la plupart du temps, elles fonctionnent, et lorsque les moteurs de recherche découvrent que vous essayez de scraper leur site Web sans autorisation, ils restreignent votre accès.

Un autre obstacle auquel sont confrontés les web scrapers est représenté par les changements dans la structure d'un site web. Un petit changement dans la structure du site peut nous faire perdre beaucoup de temps. Les outils de web scraping nécessitent des mises à jour fréquentes pour s'adapter et faire le travail.

Un autre défi auquel sont confrontés les web scrapers est appelé géoblocage. En fonction de votre emplacement physique, un site web peut vous interdire complètement l'accès si les requêtes proviennent de régions non fiables.

Pour relever ces défis et vous aider à vous concentrer sur le développement de votre produit, nous avons créé WebScrapingAPI. Il s'agit d'une API évolutive de niveau entreprise, facile à utiliser, qui vous aide à collecter et à gérer des données HTML. Nous sommes obsédés par la vitesse, nous utilisons un réseau mondial de proxys rotatifs et nous comptons déjà plus de 10 000 clients qui utilisent nos services. Si vous estimez ne pas avoir le temps de développer un outil de web scraping à partir de zéro, vous pouvez essayer WebScrapingAPI en utilisant l'offre gratuite.

API : la solution simple pour le web scraping

La plupart des applications web fournissent une API qui permet aux utilisateurs d'accéder à leurs données de manière prédéfinie et organisée. L'utilisateur envoie une requête à un point de terminaison spécifique et l'application répond en fournissant toutes les données demandées. Le plus souvent, les données sont déjà formatées sous forme d'objet JSON.

Lorsque vous utilisez une interface de programmation d'application, vous n'avez généralement pas à vous soucier des obstacles mentionnés précédemment. Cela dit, les API peuvent également faire l'objet de mises à jour. Dans ce cas, l'utilisateur doit toujours garder un œil sur l'API qu'il utilise et mettre à jour le code en conséquence pour ne pas perdre ses fonctionnalités.

De plus, la documentation d'une API revêt une grande importance. Si une fonctionnalité de l'API n'est pas clairement documentée, l'utilisateur perd beaucoup de temps.

Comprendre le Web

Une bonne compréhension d’Internet nécessite de nombreuses connaissances. Passons en revue une brève introduction à tous les termes dont vous avez besoin pour mieux comprendre le web scraping.

Le protocole HTTP (HyperText Transfer Protocol) est à la base de tout échange de données sur le Web. Comme son nom l'indique, HTTP est un protocole client-serveur. Un client HTTP, tel qu'un navigateur Web, établit une connexion avec un serveur HTTP et envoie un message, par exemple : « Salut ! Ça va ? Tu peux me passer ces images ? ». Le serveur renvoie généralement une réponse, sous forme de code HTML, puis ferme la connexion.

Imaginons que vous deviez vous rendre sur Google. Si vous saisissez l'adresse dans le navigateur web et appuyez sur Entrée, le client HTTP (le navigateur) enverra le message suivant au serveur :

GET / HTTP/1.1
Host: google.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/web\p,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch, br
Connection: keep-aliveUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36

La première ligne du message contient la méthode de requête (GET), le chemin vers lequel nous avons envoyé la requête (dans notre cas, il s'agit simplement de « / » car nous avons uniquement accédé à www.google.com), la version du protocole HTTP, ainsi que plusieurs en-têtes, comme Connection ou User-Agent.

Parlons des champs d'en-tête les plus importants pour le processus :

  • Host : le nom de domaine du serveur auquel vous avez accédé après avoir saisi l'adresse dans le navigateur Web et appuyé sur Entrée.
  • User-Agent : ici, nous pouvons voir des détails concernant le client qui a effectué la requête. J'utilise un MacBook, comme vous pouvez le voir dans la partie __(Macintosh; Intel Mac OS X 10_11_6)__, et Chrome comme navigateur web __(Chrome/56.0.2924.87)__.
  • Accept : en utilisant cet en-tête, le client impose au serveur de ne lui envoyer que certains types de réponses, comme application/JSON ou text/plain.
  • Referrer : Ce champ d'en-tête contient l'adresse de la page à l'origine de la requête. Les sites web utilisent cet en-tête pour adapter leur contenu en fonction de la provenance de l'utilisateur.

Une réponse du serveur peut ressembler à ceci :

HTTP/1.1 200 OK
Server: nginx/1.4.6 (Ubuntu) Content-Type: text/html; charset=utf-8 
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>The content of the document</body>
</html>

Comme vous pouvez le voir, la première ligne contient le code de réponse HTTP : **200 OK. Cela signifie que l'action de scraping a réussi.

Maintenant, si nous avions envoyé la requête à l'aide d'un navigateur web, celui-ci aurait analysé le code HTML, récupéré tous les autres éléments tels que les fichiers CSS, JavaScript et les images, puis affiché la version finale de la page web. Dans les étapes ci-dessous, nous allons essayer d'automatiser ce processus.

Comprendre le scraping Web avec Node.js

JavaScript a été initialement créé pour aider ses utilisateurs à ajouter du contenu dynamique aux sites web. Au départ, il ne pouvait pas interagir directement avec un ordinateur ou ses données. Lorsque vous accédez à un site web, le JavaScript est lu par le navigateur et converti en quelques lignes de code que l'ordinateur peut traiter.

Voici Node.js, l'outil qui permet à JavaScript de s'exécuter non seulement côté client, mais aussi côté serveur. Node.js peut être défini comme un JavaScript libre et open source destiné à la programmation côté serveur. Il aide ses utilisateurs à créer et à exécuter rapidement des applications réseau.

const http = require('http');
const port = 8000;
const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello world!');
});
server.listen(port, () => {
  console.log(`Server running on port 8000.`);
});

Si Node.js n'est pas installé, consultez l'étape suivante pour obtenir les instructions. Sinon, créez un nouveau fichier index.js et exécutez-le en tapant node index.js dans un terminal, ouvrez un navigateur et rendez-vous sur localhost:8000. Vous devriez voir la chaîne suivante : « Hello world ! ».

Outils requis

Chrome - Veuillez suivre le guide d'installation disponible ici.

  • VSCode - Vous pouvez le télécharger depuis cette page et suivre les instructions pour l'installer sur votre appareil.
  • Node.js - Avant de commencer à utiliser Axios, Cheerio ou Puppeteer, nous devons installer Node.js et le gestionnaire de paquets Node (NPM). La manière la plus simple d'installer Node.js et NPM est de télécharger l'un des programmes d'installation depuis le site officiel de Node.js et de l'exécuter.

Une fois l'installation terminée, vous pouvez vérifier si Node.js est bien installé en exécutant node -v et npm -v dans une fenêtre de terminal. La version doit être supérieure à v14.15.5. Si vous rencontrez des difficultés avec ce processus, il existe une autre méthode pour installer Node.js.

Créons maintenant un nouveau projet NPM. Créez un nouveau dossier pour le projet et exécutez npm init -y. Passons maintenant à l'installation des dépendances.

  • Axios : une bibliothèque JavaScript utilisée pour effectuer des requêtes HTTP depuis Node.js. Exécutez npm install axios dans le dossier nouvellement créé.
  • Cheerio : une bibliothèque open source qui nous aide à extraire des informations utiles en analysant le balisage et en fournissant une API pour manipuler les données obtenues. Pour utiliser Cheerio, vous pouvez sélectionner des balises d'un document HTML à l'aide de sélecteurs. Un sélecteur se présente ainsi : $("div"). Ce sélecteur spécifique nous permet de sélectionner tous les éléments <div> d'une page.

Pour installer Cheerio, veuillez exécuter la commande npm install cheerio dans le dossier du projet.

  • Puppeteer : une bibliothèque Node.js qui permet de contrôler Chrome ou Chromium en fournissant une API de haut niveau.

Pour utiliser Puppeteer, vous devez l'installer à l'aide d'une commande similaire : npm install puppeteer. Notez que lorsque vous installez ce paquet, une version récente de Chromium, garantie compatible avec votre version de Puppeteer, sera également installée.

Inspection de la source de données

Tout d'abord, vous devez accéder au site web que vous souhaitez scraper à l'aide de Chrome ou de tout autre navigateur web. Pour réussir à extraire les données dont vous avez besoin, vous devez comprendre la structure du site web.

Inspection du site web ciblé

Une fois que vous avez réussi à accéder au site web, utilisez-le comme le ferait un utilisateur normal. Si vous avez accédé au subreddit /r/dundermifflin, vous pouvez consulter les publications sur la page principale en cliquant dessus, en consultant les commentaires et les votes positifs, et même en triant les publications par nombre de votes sur une période donnée.

Comme vous pouvez le constater, le site web contient une liste de publications, et chaque publication comporte des votes positifs et des commentaires.

Vous pouvez comprendre une grande partie des données d'un site web simplement en regardant son URL. Dans ce cas, https://www.old.reddit.com/r/DunderMifflin représente l'URL de base, le chemin qui nous mène à la communauté Reddit « The Office ». Lorsque vous commencez à trier les publications par nombre de votes, vous pouvez voir que l'URL de base change pour devenir https://www.old.reddit.com/r/DunderMifflin/top/?t=year.

Les paramètres de requête sont des extensions de l'URL qui servent à définir un contenu ou des actions spécifiques en fonction des données transmises. Dans notre cas, « ?t=year » représente la période sélectionnée pour laquelle nous souhaitons voir les messages les plus plébiscités.

Tant que vous restez sur ce subreddit spécifique, l'URL de base restera la même. Seuls les paramètres de requête changeront. Nous pouvons les considérer comme des filtres appliqués à la base de données pour récupérer les données souhaitées. Vous pouvez modifier la période pour ne voir que les publications les plus plébiscitées du dernier mois ou de la dernière semaine en modifiant simplement l'URL.

Inspection à l'aide des outils de développement

Dans les étapes suivantes, vous allez en apprendre davantage sur la manière dont les informations sont organisées sur la page. Vous devrez le faire pour mieux comprendre ce que nous pouvons réellement extraire de notre source.

Les outils de développement vous aident à explorer de manière interactive le modèle objet de document (DOM) du site web. Nous allons utiliser les outils de développement de Chrome, mais vous pouvez utiliser n'importe quel navigateur web avec lequel vous êtes à l'aise. Dans Chrome, vous pouvez les ouvrir en cliquant avec le bouton droit n'importe où sur la page et en sélectionnant l'option « Inspecter ».

Dans le nouveau menu qui s'affiche à l'écran, sélectionnez l'onglet « Éléments ». Cela affichera la structure HTML interactive du site web.

Vous pouvez interagir avec le site web en modifiant sa structure, en développant et en réduisant des éléments, voire en les supprimant. Notez que ces modifications ne seront visibles que par vous.

Les expressions régulières et leur rôle

Les expressions régulières, également appelées RegEx, vous aident à créer des règles qui vous permettent de trouver et de gérer différentes chaînes de caractères. Si vous avez un jour besoin d'analyser de grandes quantités d'informations, la maîtrise des expressions régulières peut vous faire gagner beaucoup de temps.

Lorsque vous commencez à utiliser les expressions régulières, elles peuvent sembler un peu trop compliquées, mais en réalité, elles sont assez faciles à utiliser. Prenons l'exemple suivant : \d. En utilisant cette expression, vous pouvez facilement extraire n'importe quel chiffre compris entre 0 et 9. Bien sûr, il en existe de bien plus complexes, comme : ^(\(\d{3}\)|^\d{3}[.-]?)?\d{3}[.-]?\d{4}$. Cela correspond à un numéro de téléphone, avec ou sans parenthèses autour de l'indicatif régional, ou avec ou sans points pour séparer les chiffres.

Comme vous pouvez le constater, les expressions régulières sont assez faciles à utiliser et peuvent s'avérer très puissantes si vous consacrez suffisamment de temps à les maîtriser.

Comprendre Cheerio.js

Une fois que vous avez installé avec succès toutes les dépendances présentées précédemment et inspecté le DOM à l'aide des outils de développement, vous pouvez passer au scraping proprement dit.

Une chose à garder à l'esprit est que si la page que vous essayez de scraper est une SPA (application monopage), Cheerio n'est peut-être pas la meilleure solution. La raison est que Cheerio ne peut pas vraiment fonctionner comme un navigateur web. C'est pourquoi, dans les étapes suivantes, nous allons utiliser Puppeteer. Mais d'ici là, découvrons à quel point Cheerio est puissant.

Pour tester les fonctionnalités de Cheerio, essayons de collecter tous les titres des messages sur le subreddit présenté précédemment : /r/dundermifflin.

Créons un nouveau fichier nommé index.js et tapons ou copions simplement les lignes suivantes :

const axios = require("axios");
const cheerio = require("cheerio");
const fetchTitles = async () => {
	try {
		const response = await axios.get('https://old.reddit.com/r/DunderMifflin/');
                const html = response.data;
		const $ = cheerio.load(html);
		const titles = [];
		$('div > p.title > a').each((_idx, el) => {
			const title = $(el).text()
			titles.push(title)
		});
		return titles;
	} catch (error) {
		throw error;
	}};
fetchTitles().then((titles) => console.log(titles));

Pour mieux comprendre le code ci-dessus, nous allons expliquer ce que fait la fonction asynchrone fetchTitles() :

Tout d’abord, nous effectuons une requête GET vers l’ancien site web de Reddit à l’aide de la bibliothèque Axios. Le résultat de cette requête est ensuite chargé par Cheerio à la ligne 10. À l'aide des outils de développement, nous avons découvert que les éléments contenant les informations souhaitées sont quelques balises d'ancrage. Pour être sûrs de ne sélectionner que les balises d'ancrage contenant le titre du message, nous allons également sélectionner leurs éléments parents à l'aide du sélecteur suivant : $('div > p.title &g;t; a')

Pour récupérer chaque titre individuellement et non pas simplement un gros bloc de lettres sans signification, nous devons parcourir chaque publication à l'aide de la fonction each(). Enfin, l'appel de text() sur chaque élément me renverra le titre de cette publication spécifique.

Pour l'exécuter, il suffit de taper node index.js dans le terminal et d'appuyer sur Entrée. Vous devriez voir un tableau contenant tous les titres des articles.

DOM pour NodeJS

Comme le DOM d'une page web n'est pas directement accessible à Node.js, nous pouvons utiliser JSDOM. Selon sa documentation, JSDOM est une implémentation pure JavaScript de nombreuses normes web, notamment les normes DOM et HTML du WHATWG, destinée à être utilisée avec Node.js.

En d'autres termes, grâce à JSDOM, nous pouvons créer un DOM et le manipuler en utilisant les mêmes méthodes que celles que nous utiliserions pour manipuler celui du navigateur web.

JSDOM vous permet d'interagir avec un site web que vous devez explorer. Si vous êtes familier avec la manipulation du DOM du navigateur web, comprendre le fonctionnement de JSDOM ne vous demandera pas beaucoup d'efforts.

Pour mieux comprendre le fonctionnement de JSDOM, installons-le, créons un nouveau fichier index.js et saisissons ou copions le code suivant :

const { JSDOM } = require('jsdom')
const { document } = new JSDOM(
  '<h1 class="string">Dunder mifflin, the people person\'s paper people!</h2>'
).window
const string = document.querySelector('.string')
console.log(string.innerHTML)
string.textContent = 'Hello world'
console.log(string.innerHTML)

Comme vous pouvez le voir, JSDOM crée un nouveau modèle d'objet document (DOM) qui peut être manipulé à l'aide de la même méthode que celle utilisée pour manipuler le DOM du navigateur. À la ligne 3, un nouvel élément h1 est créé dans le DOM. À l'aide de la classe attribuée à l'en-tête, nous sélectionnons l'élément à la ligne 7 et modifions son contenu à la ligne 10. Vous pouvez constater la différence en affichant l'élément DOM avant et après la modification.

Pour l'exécuter, ouvrez un nouveau terminal, tapez node index.js, puis appuyez sur Entrée.

Bien sûr, vous pouvez effectuer des actions bien plus complexes à l'aide de JSDOM, comme ouvrir une page web et interagir avec elle, remplir des formulaires et cliquer sur des boutons.

Pour ce que ça vaut, JSDOM est une bonne option, mais Puppeteer a gagné beaucoup de popularité ces dernières années.

Comprendre Puppeteer : comment décortiquer les pages JavaScript

Avec Puppeteer, vous pouvez effectuer la plupart des tâches que vous pouvez réaliser manuellement dans un navigateur web, comme remplir un formulaire, générer des captures d'écran de pages ou automatiser les tests d'interface utilisateur.

Essayons de mieux comprendre son fonctionnement en prenant une capture d'écran de la communauté Reddit /r/dundermifflin. Si vous avez déjà installé la dépendance, passez à l'étape suivante. Sinon, veuillez exécuter npm i puppeteer dans le dossier du projet. Créez maintenant un nouveau fichier index.js et tapez ou copiez le code suivant :

const puppeteer = require('puppeteer')
async function takeScreenshot() {
	try {
		const URL = 'https://www.old.reddit.com/r/dundermifflin/'
		const browser = await puppeteer.launch()
		const page = await browser.newPage()
		await page.goto(URL)
		await page.pdf({ path: 'page.pdf' })
		await page.screenshot({ path: 'screenshot.png' })
		await browser.close()
	} catch (error) {
		console.error(error)
	}
}
takeScreenshot()

Nous avons créé la fonction asynchrone takeScreenshot().

Comme vous pouvez le voir, une instance du navigateur est d'abord lancée à l'aide de la commande puppeteer.launch(). Ensuite, nous créons une nouvelle page et, en appelant la fonction goto() avec l'URL comme paramètre, la page créée précédemment sera redirigée vers cette URL spécifique. Les méthodes pdf() et screenshot() nous permettent de créer un nouveau fichier PDF et une image contenant la page web sous forme visuelle.

Enfin, l'instance du navigateur est fermée à la ligne 13. Pour l'exécuter, tapez node index.js dans le terminal et appuyez sur Entrée. Vous devriez voir deux nouveaux fichiers dans le dossier projects, nommés page.pdf et screenshot.png.

Alternative à Puppeteer

Si vous n'êtes pas à l'aise avec Puppeteer, vous pouvez toujours utiliser une alternative telle que NightwatchJS, NightmareJS ou CasperJS.

Prenons l'exemple de Nightmare. Comme il utilise Electron au lieu de Chromium, la taille du bundle est légèrement inférieure. Nightmare peut être installé en exécutant la commande npm install nightmare. Nous allons essayer de reproduire le processus précédemment réussi consistant à prendre une capture d'écran de la page en utilisant Nightmare à la place de Puppeteer.

Créons un nouveau fichier index.js et saisissons ou copions le code suivant :

const Nightmare = require('nightmare')
const nightmare = new Nightmare()
return nightmare.goto('https://www.old.reddit.com/r/dundermifflin')
	.screenshot('./nightmare-screenshot.png')
 	.end()
	.then(() => {
		console.log('Done!')
	})
	.catch((err) => {
		console.error(err)
	})

Comme vous pouvez le voir à la ligne 2, nous créons une nouvelle instance de Nightmare, nous pointons le navigateur vers la page web dont nous voulons faire une capture d'écran, nous prenons et enregistrons la capture d'écran à la ligne 5 et nous terminons la session Nightmare à la ligne 6.

Pour l'exécuter, tapez node index.js dans le terminal et appuyez sur Entrée. Vous devriez voir deux nouveaux fichiers nightmare-screenshot.png dans le dossier projects.

Points clés

Si vous êtes toujours là, félicitations ! Vous disposez de toutes les informations nécessaires pour créer votre propre scraper web. Prenons une minute pour résumer ce que vous avez appris jusqu'à présent :

  • Un scraper web est un logiciel qui vous aide à automatiser le processus fastidieux de collecte de données utiles sur des sites web tiers.
  • Les utilisateurs ont recours aux web scrapers pour toutes sortes de récupérations de données : analyse de marché, comparaison de prix ou génération de prospects.
  • Les clients HTTP, comme les navigateurs web, vous aident à envoyer des requêtes à un serveur et à recevoir une réponse.
  • JavaScript a été initialement créé pour aider ses utilisateurs à ajouter du contenu dynamique aux sites web. Node.js est un outil qui permet à JavaScript de s'exécuter non seulement côté client, mais aussi côté serveur.
  • Cheerio est une bibliothèque open source qui nous aide à extraire des informations utiles en analysant le code HTML et en fournissant une API pour manipuler les données obtenues.
  • Puppeteer est une bibliothèque Node.js utilisée pour contrôler Chrome ou Chromium en fournissant une API de haut niveau. Grâce à elle, vous pouvez effectuer la plupart des tâches que vous pouvez réaliser manuellement dans un navigateur web, comme remplir un formulaire, générer des captures d'écran de pages ou automatiser des processus.
  • Vous pouvez comprendre une grande partie des données d'un site web simplement en regardant son URL.
  • Les outils de développement vous aident à explorer de manière interactive le modèle objet de document (DOM) du site web.
  • Les expressions régulières vous aident à créer des règles qui vous permettent de trouver et de gérer différentes chaînes de caractères.
  • JSDOM est un outil qui crée un nouveau Modèle d'objet document pouvant être manipulé à l'aide de la même méthode que celle utilisée pour manipuler le DOM du navigateur.

Nous espérons que ces instructions étaient claires et que vous avez pu obtenir toutes les informations nécessaires pour votre prochain projet. Si vous ne souhaitez toujours pas vous en charger vous-même, vous pouvez toujours essayer WebScrapingAPI.

Merci d'être resté avec nous jusqu'au bout !

À propos de l'auteur
Robert Sfichi, Développeur full-stack @ WebScrapingAPI
Robert SfichiDéveloppeur full-stack

Robert Sfichi fait partie de l'équipe de WebScrapingAPI ; il contribue au développement du produit et aide à mettre en place des solutions fiables au service de la plateforme et de ses utilisateurs.

Commencez à créer

Prêt à faire évoluer votre système de collecte de données ?

Rejoignez plus de 2 000 entreprises qui utilisent WebScrapingAPI pour extraire des données Web à l'échelle de l'entreprise, sans aucun coût d'infrastructure.