Retour au blog
Guides
Mihnea-Octavian Manolache24 avril 20238 min de lecture

Comment utiliser un proxy avec Node Fetch et créer un outil de scraping Web

Comment utiliser un proxy avec Node Fetch et créer un outil de scraping Web

Qu'est-ce qu'un proxy et pourquoi l'utiliser pour le web scraping ?

En réseau informatique, les proxys agissent comme des « intermédiaires » entre un client et un serveur. L'architecture d'un serveur proxy est assez complexe, mais en gros, voici ce qui se passe lorsque vous utilisez un proxy :

  • Vous vous « connectez » au serveur proxy et spécifiez la destination (le serveur) que vous essayez d'atteindre (de scraper)
  • Le serveur proxy se connecte à votre cible et récupère les résultats (les fichiers HTML d'un site web, par exemple)
  • Le serveur proxy vous renvoie ensuite la réponse qu’il a reçue du serveur de destination
Diagram showing a scraper routing requests through a proxy to a target website

Dans cette chaîne, votre adresse IP reste masquée au serveur de destination, car vous ne vous y connectez jamais réellement. Et c’est principalement la raison pour laquelle les proxys jouent un rôle si important dans le web scraping. Ils « masquent » l’adresse IP du web scraper, afin qu’il ne soit pas bloqué par les systèmes anti-bot.

Pourquoi utiliser node-fetch pour le web scraping ?

Si JavaScript est votre langage de programmation préféré, il existe de nombreux clients HTTP que vous pouvez utiliser pour créer un scraper web. Parmi les plus populaires, on trouve axios, got et quelques autres répertoriés ici. Mais node-fetch reste l’un des paquets npm les plus téléchargés, et il y a une raison à cela.

Tout d’abord, c’est le premier paquet à avoir implémenté l’API Fetch dans Node.js. Ensuite, à partir de la version 17.5.0, l’équipe Node.js a intégré l’API Fetch, de sorte qu’elle ne soit plus nécessaire en tant que dépendance tierce. À ce jour, dans la version 19.3.0 de Node.js, fetch est toujours marqué comme expérimental. Node-fetch reste donc la solution la plus stable.

En matière de scraping, node-fetch est un excellent outil car, comme son nom l'indique, il sert à récupérer des ressources provenant de diverses sources. Et c'est peut-être là la définition la plus fondamentale du scraping.

Comment utiliser node-fetch avec des proxys ?

Pour faire court, il n'existe pas de méthode intégrée pour utiliser un proxy avec node-fetch. Ainsi, si vous souhaitez créer un scraper web, mais que votre infrastructure repose sur node-fetch, vous risquez d'exposer votre véritable adresse IP. Cela signifie que vous risquez d'être bloqué par des logiciels anti-bot.

Heureusement, il existe des solutions de contournement. L'une d'entre elles nous est proposée par Nathan Rajlich, qui a développé un module implémentant http.Agent, appelé https-proxy-agent. L'installation est disponible via npm. De plus, son implémentation avec node-fetch est assez simple :

import fetch from 'node-fetch';

import HttpsProxyAgent from "https-proxy-agent";

const fetch_proxy = async () => {

   	const proxy = new HttpsProxyAgent('http://1.255.134.136:3128');

   	const response = await fetch('https://httpbin.org/ip', { agent: proxy});

   	const data = await response.text();

   	console.log(data);

}

fetch_proxy()

Pour les besoins de ce test, j'ai utilisé un proxy gratuit de Proxy Scrape. Comme prévu, la réponse indique que la requête provient de l'adresse IP du proxy, et non de mon adresse IP locale :

"origin": "1.255.134.136"

Une autre option consiste à utiliser node-fetch-with-proxy. Ce paquet utilise proxy-agent comme dépendance propre, en plus de node-fetch. Pour que cela fonctionne, il suffit de définir la variable d’environnement « HTTP_PROXY ». Elle prend comme valeur l’adresse IP et le numéro de port de votre serveur proxy. Vous pouvez ensuite utiliser la syntaxe standard de node-fetch pour effectuer vos requêtes, qui seront automatiquement acheminées vers le serveur proxy. Voici un exemple :

import fetch from "node-fetch-with-proxy";

fetch('http://httpbin.org/ip')

.then(res => res.json())

.then(json => console.log(json));

Comment créer un scraper web à l'aide d'un proxy avec node-fetch ?

Pour commencer, nous avons déjà créé un scraper web. Les exemples de code ci-dessus font exactement ce que fait n'importe quel scraper web, à savoir collecter des données depuis un site web. Cependant, dans un scénario réel, un scraper web est un peu plus complexe. Par exemple, les données brutes doivent être traitées, ou nous devons vérifier et analyser les en-têtes ou les cookies collectés. Plongeons donc un peu plus en profondeur et transformons notre premier exemple en un véritable scraper. Définissons quelques attentes :

  • Nous devrions pouvoir renvoyer le code HTML brut
  • Nous devrions pouvoir renvoyer la réponse complète sous forme d'objet JSON
  • Nous devrions pouvoir extraire des éléments en fonction de sélecteurs spécifiques

En supposant que vous ayez déjà installé node-fetch et https-proxy-agent, il nous faudra encore une chose : un parseur HTML. J'utilise toujours cheerio pour le web scraping. Veillez donc à l'installer dans votre projet. Cela étant dit, commençons :

#1 : Importer les dépendances

La première chose à faire est d'importer les paquets dont nous avons parlé plus haut. Je pense que cette partie ne nécessite aucune explication supplémentaire :

import fetch from 'node-fetch';

import HttpsProxyAgent from "https-proxy-agent";

import * as cheerio from 'cheerio';

#2 : Logique du scraper

Notre scraper doit être capable d'effectuer trois actions : renvoyer le code HTML d'une ligne, renvoyer la réponse complète et renvoyer un élément en fonction de son sélecteur CSS. Nous avons déjà partiellement implémenté l'une d'entre elles. Mais divisons le tout en trois fonctions :

const raw_html = async (proxyServer, targetURL) => {

   const proxy = new HttpsProxyAgent(proxyServer);

   const response = await fetch(targetURL, { agent: proxy});

   const data = await response.text();

   return data;

}

const json_response = async (proxyServer, targetURL) => {

   const proxy = new HttpsProxyAgent(proxyServer);

   const response = await fetch(targetURL, { agent: proxy});

   const data = {

       url: response.url,

       status: response.status,

       Headers: response.headers,

       body: await response.text()

   }

   return data;

}

const select_css = async (proxyServer, targetURL, cssSelector) => {

   const proxy = new HttpsProxyAgent(proxyServer);

   const response = await fetch(targetURL, { agent: proxy});

   const html = await response.text();

   const $ = cheerio.load(html);

   return $(cssSelector).text();

}

#3 : Analyseur d'arguments

Nous pouvons utiliser les arguments du terminal pour distinguer les trois options que nous avons implémentées dans notre scraper. Il existe des options permettant d’analyser les arguments de ligne de commande dans Node, mais je préfère rester simple. C’est pourquoi nous utiliserons process.argv, qui génère un tableau d’arguments. Notez que les deux premiers éléments de ce tableau sont « node » et le nom de votre script. Par exemple, si vous exécutez `node scraper.js raw_html`, le tableau d’arguments ressemblera à ceci :

[

  '/usr/local/bin/node',

  'path_to_directory/scraper.js',

  'raw_html'

]

En ignorant les deux premiers éléments, nous utiliserons la logique suivante :

  • le premier argument spécifiera la fonction que nous voulons exécuter ;
  • le deuxième indiquera notre cible (le site web que nous voulons scraper) ;
  • le troisième indiquera le serveur proxy ;
  • et le quatrième indiquera le sélecteur CSS.

La commande permettant d'exécuter notre scraper devrait donc ressembler à ceci :

~ » node scraper.js raw_html https://webscrapingapi.com http://1.255.134.136:3128 

Cela revient simplement à extraire le code HTML brut de la page d'accueil de WebScrapingAPI et à utiliser http://1.255.134.136 comme intermédiaire proxy. Il ne reste plus qu'à coder la logique pour ces arguments, de sorte que notre code comprenne la commande d'exécution :

const ACTION = process.argv[2]

const TARGET = process.argv[3]

const PROXY = process.argv[4]

const SELECTOR = process.argv[5]
switch (ACTION) {

   case 'raw_html':

console.log(await raw_html(PROXY, TARGET))

break

   case 'json_response':

console.log(await json_response(PROXY, TARGET))

break

   case 'select_css':

SELECTOR ? console.log(await select_css(PROXY, TARGET, SELECTOR)) : console.log('Please specify a CSS selector!')

break

   default:

conssole.log('Please choose between `raw_html`, `json_response` and `select_css`')

}

Et c'est à peu près tout. Félicitations ! Vous avez réussi à créer un scraper web entièrement fonctionnel en utilisant un proxy avec node-fetch. Je vous mets maintenant au défi d'ajouter davantage de fonctionnalités à ce scraper, de créer votre propre version et de l'utiliser comme atout dans votre portfolio personnel.

L'utilisation d'un proxy avec node-fetch peut ne pas suffire pour le web scraping

Comme j'aime à le dire, le scraping furtif ne se résume pas à cacher votre adresse IP. En réalité, l'utilisation d'un serveur proxy pour votre scraper web ne constitue qu'une couche de protection contre les logiciels anti-bot. Une autre couche consiste à modifier votre agent utilisateur en [définissant des en-têtes personnalisés pour votre requête] (LIEN https://trello.com/c/n8xZswSI/14-2-8-january-article-13-http-headers-with-axios).

Chez Web Scraping API, par exemple, nous disposons d’une équipe dédiée qui travaille sur des techniques d’évasion personnalisées. Certaines d’entre elles vont jusqu’à modifier les valeurs par défaut du navigateur sans interface graphique afin d’éviter le fingerprinting.

De plus, comme les sites modernes affichent le contenu de manière dynamique à l'aide de JavaScript, un simple client HTTP tel que node-fetch peut ne pas suffire. Vous pourriez envisager d'utiliser un véritable navigateur web. Selenium pour Python ou Puppeteer pour Node sont deux options que vous pourriez explorer à cet égard.

Conclusions

Utiliser un proxy avec node-fetch est un excellent point de départ pour créer un scraper web. Cependant, vous devez tenir compte du fait que les deux ne sont pas « directement compatibles » et que vous devrez utiliser une solution tierce pour les relier. Heureusement, les possibilités sont nombreuses et la communauté JavaScript est toujours ravie d’aider les débutants.

Développer un scraper furtif est toutefois plus difficile et vous devrez imaginer des techniques d'évasion plus complexes. Mais j'aime voir une opportunité dans tout. Pourquoi ne pas mettre à profit ce que vous avez appris aujourd'hui et aller plus loin ? Avec un peu de chance, à la fin, vous aurez créé le meilleur scraper web écrit avec node-fetch et des proxys. Comme toujours, mon conseil est de continuer à apprendre !

À propos de l'auteur
Mihnea-Octavian Manolache, Développeur Full Stack @ WebScrapingAPI
Mihnea-Octavian ManolacheDéveloppeur Full Stack

Mihnea-Octavian Manolache est ingénieur Full Stack et DevOps chez WebScrapingAPI, où il développe des fonctionnalités pour les produits et assure la maintenance de l'infrastructure qui garantit le bon fonctionnement de la plateforme.

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.