Noon est l'un des plus grands marchés e-commerce au Moyen-Orient, servant des millions d'acheteurs aux Émirats arabes unis, en Arabie saoudite et en Égypte. Son catalogue couvre l'électronique, la mode, la beauté et l'épicerie, et les prix et évaluations affichés sur ces pages de résultats constituent un signal public clair pour quiconque suit un concurrent, étudie une catégorie ou construit un outil de suivi des prix. Les données sont directement accessibles sur chaque page de recherche : titres de produits, prix, notes, marques et un lien vers chaque article.

Ce guide vous montre comment extraire des données Noon avec JavaScript et Node.js en utilisant cheerio. Vous construisez un petit scraper fonctionnel qui récupère une page de résultats de recherche Noon via la Crawling API, analyse le titre, le prix, la note, la marque et le lien de chaque produit, gère la pagination sur les pages de résultats et exporte le tout au format JSON et CSV. L'ensemble du guide se limite aux données publiques des pages de listes de produits, et la section sur la légalité vers la fin n'est pas un texte boilerplate, alors lisez-la avant de l'utiliser à grande échelle.

Ce que vous allez construire

Un script Node.js qui prend une URL de recherche Noon publique et une requête, récupère le HTML rendu via la Crawling API, et extrait un enregistrement structuré pour chaque produit de la liste. Nous utilisons la vitrine des Émirats arabes unis et la requête « smartphones » comme exemple de référence et extrayons ces champs par article :

  • Titre le nom du produit, lu depuis l'élément data-qa="product-name".
  • Prix le montant numérique affiché sur la carte, par exemple « 1 799 ».
  • Devise l'intitulé de devise situé à côté du montant, comme « AED ».
  • Note le texte de la note en étoiles lorsque le produit a des avis.
  • Marque l'intitulé de marque affiché au-dessus du nom du produit sur la carte.
  • Lien l'URL absolue vers la page individuelle du produit.

Pourquoi une requête simple échoue sur Noon

Si vous demandez une URL de recherche Noon avec un client HTTP brut, vous obtenez rarement la grille de produits en retour. Deux facteurs jouent contre vous. Premièrement, Noon génère ses cartes de listes dans le navigateur avec JavaScript, de sorte que le HTML initial est une coquille presque vide jusqu'à ce que les scripts de la page s'exécutent et que les données de produits se chargent via AJAX. Deuxièmement, Noon détecte le trafic automatisé : les adresses IP de centre de données et les schémas de requêtes qui ne ressemblent pas à un vrai navigateur sont soumis à un CAPTCHA, limités en débit ou bloqués avant même d'atteindre les listes rendues.

Un scraper Noon fonctionnel a donc besoin de deux choses en une seule requête : un navigateur qui rend effectivement la page et attend le contenu AJAX, et une IP que la plateforme reconnaît comme un vrai visiteur. Vous pouvez assembler cela vous-même avec un navigateur sans interface et un pool de proxies résidentiels rotatifs, mais les assembler et les maintenir en bon état représente l'essentiel du travail. La Crawling API réunit les deux en un seul appel : vous lui envoyez l'URL, elle rend la page derrière une IP de confiance, attend le contenu dynamique et retourne le HTML finalisé que vous pouvez analyser avec cheerio.

Attendre le contenu AJAX

Noon charge ses cartes de produits de manière asynchrone, donc les paramètres les plus importants sont ajax_wait et page_wait. Définir ajax_wait: 'true' indique à la Crawling API de maintenir la requête jusqu'à ce que les téléchargements en arrière-plan se stabilisent, et page_wait ajoute un délai fixe (en millisecondes) pour que les cartes lentes aient le temps de s'afficher avant que le HTML ne soit capturé.

Prérequis

Vous avez besoin de quelques éléments en place avant d'écrire du code. Aucun d'eux ne prend longtemps.

Connaissances de base en JavaScript et Node.js. Vous devez être à l'aise pour écrire et exécuter un script Node et installer des packages avec npm. Si vous débutez avec Node, la documentation officielle ou tout cours pour débutants vous amènera au niveau supposé par ce tutoriel. Le guide d'accompagnement sur la façon de construire un scraper web avec Node.js couvre les bases si vous souhaitez un rappel.

Node.js 16 ou version ultérieure. Confirmez votre version avec node --version. Si vous ne l'avez pas, installez-le depuis le site web de Node.js ou via un gestionnaire de versions comme nvm.

Un compte Crawlbase et un token. Inscrivez-vous, ouvrez votre tableau de bord et copiez votre token depuis la page de documentation du compte. Le niveau gratuit vous donne jusqu'à 20 000 requêtes sans carte bancaire. Traitez le token comme un mot de passe : il authentifie vos requêtes, gardez-le donc en dehors du contrôle de version.

Configurer le projet

Créez un dossier de projet, initialisez-le et installez les deux bibliothèques dont le scraper a besoin.

bash
node --version

mkdir noon-scraper && cd noon-scraper
npm init -y

npm install crawlbase cheerio

Deux dépendances font le travail : crawlbase est le client Node officiel pour la Crawling API, et cheerio analyse le HTML retourné avec une API de style jQuery afin que vous puissiez extraire des champs individuels par sélecteur CSS. Créez un fichier nommé noon-scraper.js dans ce dossier et ajoutez le code des étapes ci-dessous.

Étape 1 : Récupérer la page de recherche rendue

Commencez par obtenir la page finalisée. Importez la classe CrawlingAPI, initialisez-la avec votre token et demandez une URL de recherche Noon avec les options d'attente AJAX définies. Vérifier le code de statut avant d'analyser permet de rendre les échecs visibles plutôt que silencieux.

javascript
const { CrawlingAPI } = require('crawlbase');

const api = new CrawlingAPI({ token: 'YOUR_CRAWLBASE_TOKEN' });

function searchUrl(query, page) {
  return `https://www.noon.com/uae-en/search/?q=${query}&page=${page}`;
}

const options = { ajax_wait: 'true', page_wait: '5000' };

api
  .get(searchUrl('smartphones', 1), options)
  .then((response) => {
    if (response.statusCode === 200) {
      console.log(response.body.slice(0, 500));
    }
  })
  .catch((error) => console.error('API request error:', error));

Exécutez le script avec node noon-scraper.js et vous devriez voir du vrai balisage de liste Noon en haut du corps, et non pas une coquille dépouillée. Cela confirme que le rendu et l'attente AJAX ont fonctionné avant d'écrire un seul sélecteur. Si vous n'avez pas besoin de champs personnalisés et préférez récupérer du JSON structuré sans écrire de parseur, passez autoparse: 'true' dans les options et l'API retourne des données analysées directement.

Crawlbase Crawling API

Cette première requête vient de retourner une page de recherche Noon entièrement rendue, cartes AJAX incluses, sans navigateur sans interface ni proxy de votre côté. La Crawling API exécute la page dans un vrai navigateur, attend le contenu dynamique avec ajax_wait et page_wait, fait tourner des IPs résidentielles côté serveur et gère les CAPTCHAs que Noon envoie aux scrapers, de sorte que vous obtenez le HTML finalisé en un seul appel. Pointez-la vers la recherche de smartphones sur le niveau gratuit en premier.

Étape 2 : Analyser chaque produit avec cheerio

Avec le HTML rendu en main, chargez-le dans cheerio et parcourez les cartes de produits. Noon organise chaque résultat de recherche dans un conteneur répétitif, vous sélectionnez donc chaque carte, puis lisez le titre, le prix, la devise, la note, la marque et le lien depuis l'intérieur. Lire chaque champ de manière défensive évite qu'une valeur manquante ne fasse planter l'exécution.

javascript
const cheerio = require('cheerio');

function extractProducts(html) {
  const $ = cheerio.load(html);
  const products = [];

  $('div.grid > span.productContainer').each((index, element) => {
    const card = $(element);

    const title = card
      .find('div[data-qa="product-name"]')
      .text()
      .trim();
    const price = card.find('strong.amount').text().trim();
    const currency = card.find('span.currency').text().trim();
    const rating = card.find('div.dGLdNc').text().trim();
    const brand = card.find('div[data-qa="product-brand"]').text().trim();

    const href = card.find('a').attr('href');
    const link = href ? new URL(href, 'https://www.noon.com').href : '';

    if (title && price) {
      products.push({ title, price, currency, rating, brand, link });
    }
  });

  return products;
}

Quelques détails maintiennent cette approche fidèle à la page. Le titre provient de l'élément data-qa="product-name", le prix numérique se trouve dans strong.amount, et le libellé de devise est lu séparément depuis span.currency afin que vous puissiez garder « AED » en dehors du montant. Le texte de la note réside dans div.dGLdNc et est vide pour les produits sans avis, la marque se trouve dans l'élément data-qa="product-brand", et le lien est lu depuis l'ancre href de la carte et résolu en URL absolue pour qu'il fonctionne en dehors de la page. La vérification à la fin ne pousse un enregistrement que lorsqu'un titre et un prix sont présents, ce qui élimine les emplacements publicitaires et les cartes de remplacement vides.

Les sélecteurs évoluent

Les noms de classe hachés de Noon (dGLdNc et similaires) sont générés par son processus de construction et changent sans préavis. Traitez les sélecteurs ci-dessus comme un modèle de départ, pas comme un contrat. Lorsqu'un champ revient vide, réinspectez la page en direct dans les outils de développement de votre navigateur et mettez à jour le sélecteur. Les attributs data-qa stables ont tendance à survivre plus longtemps que les classes hachées, alors préférez-les là où la page en propose un. La maintenance périodique des sélecteurs est normale pour tout scraper en production.

Étape 3 : Gérer la pagination sur les pages de résultats

Une page de recherche est une démonstration ; une vraie exécution parcourt l'ensemble complet des résultats. Noon pagine sa recherche avec un paramètre de requête page, vous récupérez donc chaque page à tour de rôle, l'analysez avec la fonction de l'étape 2, et vous arrêtez lorsqu'une page revient sans produits. Cette vérification de page vide est ce qui vous empêche de boucler au-delà de la fin des résultats.

javascript
async function fetchPage(query, page) {
  const options = { ajax_wait: 'true', page_wait: '5000' };
  const response = await api.get(searchUrl(query, page), options);
  if (response.statusCode === 200) return response.body;
  console.error(`Failed to fetch page ${page}: ${response.statusCode}`);
  return null;
}

async function scrapeAllPages(query, maxPages) {
  const all = [];
  for (let page = 1; page <= maxPages; page++) {
    console.log(`Scraping page ${page}...`);
    const html = await fetchPage(query, page);
    if (!html) break;

    const products = extractProducts(html);
    if (products.length === 0) {
      console.log('No more results found. Stopping.');
      break;
    }
    all.push(...products);
  }
  return all;
}

L'assistant fetchPage encapsule une seule requête et retourne null en cas de statut non-200, et scrapeAllPages boucle de la page 1 jusqu'à maxPages, s'arrêtant dès qu'une page renvoie zéro produit. Comme chaque requête rend une page complète, maintenir maxPages à un niveau modeste pendant les tests est la bonne approche : chaque requête rendue en JavaScript coûte plus de crédits qu'une requête simple, alors confirmez le parseur sur une ou deux pages avant d'augmenter le nombre.

Étape 4 : Assembler le script complet avec export JSON et CSV

Maintenant, reliez la récupération, l'analyse et la pagination en un script fonctionnel, puis écrivez les enregistrements sur le disque en formats JSON et CSV.

javascript
const fs = require('fs');
const { CrawlingAPI } = require('crawlbase');
const cheerio = require('cheerio');

const api = new CrawlingAPI({ token: 'YOUR_CRAWLBASE_TOKEN' });

function searchUrl(query, page) {
  return `https://www.noon.com/uae-en/search/?q=${query}&page=${page}`;
}

function extractProducts(html) {
  const $ = cheerio.load(html);
  const products = [];

  $('div.grid > span.productContainer').each((index, element) => {
    const card = $(element);
    const title = card.find('div[data-qa="product-name"]').text().trim();
    const price = card.find('strong.amount').text().trim();
    const currency = card.find('span.currency').text().trim();
    const rating = card.find('div.dGLdNc').text().trim();
    const brand = card.find('div[data-qa="product-brand"]').text().trim();
    const href = card.find('a').attr('href');
    const link = href ? new URL(href, 'https://www.noon.com').href : '';

    if (title && price) {
      products.push({ title, price, currency, rating, brand, link });
    }
  });

  return products;
}

async function fetchPage(query, page) {
  const options = { ajax_wait: 'true', page_wait: '5000' };
  const response = await api.get(searchUrl(query, page), options);
  if (response.statusCode === 200) return response.body;
  console.error(`Failed to fetch page ${page}: ${response.statusCode}`);
  return null;
}

async function scrapeAllPages(query, maxPages) {
  const all = [];
  for (let page = 1; page <= maxPages; page++) {
    console.log(`Scraping page ${page}...`);
    const html = await fetchPage(query, page);
    if (!html) break;
    const products = extractProducts(html);
    if (products.length === 0) break;
    all.push(...products);
  }
  return all;
}

function toCsv(rows) {
  const headers = ['title', 'price', 'currency', 'rating', 'brand', 'link'];
  const escape = (value) => `"${String(value).replace(/"/g, '""')}"`;
  const lines = [headers.join(',')];
  for (const row of rows) {
    lines.push(headers.map((h) => escape(row[h])).join(','));
  }
  return lines.join('\n');
}

async function main() {
  const query = 'smartphones';
  const maxPages = 3;
  const products = await scrapeAllPages(query, maxPages);
  if (products.length === 0) return;

  fs.writeFileSync('noon-products.json', JSON.stringify(products, null, 2));
  fs.writeFileSync('noon-products.csv', toCsv(products));
  console.log(`Saved ${products.length} products to JSON and CSV`);
}

main();

Exécutez-le avec node noon-scraper.js et vous obtenez deux fichiers : noon-products.json avec les enregistrements structurés complets et noon-products.csv prêt à être ouvert dans un tableur. L'assistant toCsv met chaque champ entre guillemets et double les guillemets intégrés, ce qui importe ici car les titres de produits sont longs et contiennent fréquemment des virgules. Changez la query pour n'importe quel terme de recherche et augmentez maxPages lorsque vous êtes prêt pour une collecte plus large.

À quoi ressemble la sortie

Le fichier JSON contient un objet par produit dans l'ordre où Noon les a retournés, chacun avec le titre, le prix, la devise, la note, la marque et le lien.

json
[
  {
    "title": "Galaxy S25 AI Dual SIM Silver Shadow 12GB RAM 256GB 5G",
    "price": "3,199",
    "currency": "AED",
    "rating": "4.5",
    "brand": "Samsung",
    "link": "https://www.noon.com/uae-en/galaxy-s25-ai-dual-sim-silver-shadow-12gb-ram-256gb-5g/N70140511V/p/"
  },
  {
    "title": "A78 5G Dual SIM Glowing Black 8GB RAM 256GB",
    "price": "899",
    "currency": "AED",
    "rating": "4.3",
    "brand": "OPPO",
    "link": "https://www.noon.com/uae-en/a78-5g-dual-sim-glowing-black-8gb-ram-256gb/N70115717V/p/"
  }
]

Le CSV reprend les mêmes lignes avec une ligne d'en-tête, il se charge donc directement dans Excel, Google Sheets ou tout pipeline de données lisant des fichiers délimités.

csv
title,price,currency,rating,brand,link
"Galaxy S25 AI Dual SIM Silver Shadow 12GB RAM 256GB 5G","3,199","AED","4.5","Samsung","https://www.noon.com/uae-en/galaxy-s25-ai-dual-sim-silver-shadow-12gb-ram-256gb-5g/N70140511V/p/"
"A78 5G Dual SIM Glowing Black 8GB RAM 256GB","899","AED","4.3","OPPO","https://www.noon.com/uae-en/a78-5g-dual-sim-glowing-black-8gb-ram-256gb/N70115717V/p/"

À partir de là, les enregistrements alimentent directement le suivi des prix et les travaux de recherche. Pour une vue plus large sur la transformation des données de liste en décisions, voyez comment utiliser le web scraping pour l'intelligence des prix, et le guide général sur le web scraping e-commerce couvre les modèles applicables à tous les marchés.

Rester non bloqué

Même avec le rendu géré, Noon surveille le trafic ressemblant à des scrapers. Quelques habitudes maintiennent une exécution saine, et elles s'appliquent à toute cible commerciale difficile.

  • Espacez vos requêtes. Introduisez un délai entre les récupérations de pages plutôt que de marteler la recherche en boucle serrée. Étaler les requêtes est le facteur le plus important pour rester sous les limites de débit de Noon.
  • Misez sur la rotation. Un pool d'adresses IP résidentielles répartit les requêtes sur de nombreuses adresses d'utilisateurs réels de sorte qu'aucune ne déclenche une limite ou un CAPTCHA. La Crawling API s'en charge pour vous ; si vous construisez votre propre pile, c'est la partie à bien maîtriser.
  • Lisez les codes de statut. Une exécution qui commence à retourner des défis ou des réponses non-200 vous indique que le débit actuel ou le niveau d'IP n'est plus suffisant. Traitez cela comme un signal pour ralentir, pas comme du bruit à ignorer.

Comme Noon s'exécute côté client, la même approche rend-puis-analyse s'applique à d'autres boutiques dynamiques. Le guide général se trouve dans comment scraper des sites web sans être bloqué, et si vous voulez la technique sous-jacente seule, comment crawler des sites web JavaScript explique le rendu plus en détail.

Est-il légal de scraper Noon ?

Savoir si le scraping de Noon est autorisé dépend des conditions d'utilisation de Noon, de votre juridiction et de ce que vous faites avec les données. Les conditions de Noon restreignent l'accès automatisé, donc le scraping peut aller à l'encontre de ces conditions quel que soit le soin apporté à votre outillage. Aucun code ici ne change cela ; il rend seulement la partie technique fonctionnelle. Lisez les Conditions d'utilisation de Noon et son robots.txt, et traitez les deux comme la limite de ce que vous collectez.

Quelques règles à respecter. Ne collectez que les données de produits publics : le titre, le prix, la devise, la note, la marque et le lien produit que tout le monde peut voir sur une page de recherche sans compte. Respectez les attentes de débit de Noon et gardez votre volume de requêtes suffisamment bas pour ne pas surcharger ses serveurs. Évitez les données personnelles, y compris tout ce qui est lié à des évaluateurs identifiables au-delà du texte d'avis public et des notes par étoiles affichés sur la page. Ne redistribuez pas les médias protégés par le droit d'auteur de Noon, comme les photographies de produits, comme s'ils vous appartenaient. Si vous prévoyez de réutiliser les données commercialement, obtenez une permission ou un accord officiel plutôt que de supposer que le silence vaut consentement.

Ce guide se limite délibérément aux données de recherche et de liste publiques car c'est la ligne qui rend le travail défendable. Il ne couvre rien derrière une connexion, les données personnelles des clients ou des vendeurs, l'historique des commandes, ni aucune tentative de contourner l'authentification ou un CAPTCHA que vous n'étiez pas censé passer. Si Noon ou l'un de ses partenaires propose un flux de données sanctionné ou une API officielle pour votre cas d'usage, c'est le bon outil lorsque vous avez besoin de grands volumes, d'une structure garantie ou de droits commerciaux. Si votre projet nécessite plus que des listes publiques, un accord officiel est la bonne voie, pas un scraper plus sophistiqué.

Récapitulatif

Points clés

  • Noon rend les listes côté client et bloque fortement. Une requête simple retourne une coquille vide ou un CAPTCHA, donc vous devez rendre la page et attendre son contenu AJAX derrière une IP de confiance avant de l'analyser.
  • La Crawling API le fait en un seul appel. Passez ajax_wait: 'true' et page_wait pour que les cartes dynamiques se chargent, et l'API fait tourner des IPs résidentielles et gère les CAPTCHAs côté serveur ; ajoutez autoparse: 'true' si vous voulez du JSON au lieu du HTML brut.
  • cheerio extrait les champs. Sélectionnez chaque span.productContainer, puis lisez le titre, le prix, la devise, la note, la marque et le lien, en préférant les attributs data-qa stables car les noms de classes hachés évoluent.
  • La pagination est un paramètre de page. Bouclez la valeur de requête page et arrêtez-vous lorsqu'une page retourne zéro produit, en gardant maxPages modeste pendant les tests car chaque requête rendue coûte plus de crédits.
  • Restez sur les données publiques. Respectez les CGU et robots.txt de Noon, espacez vos requêtes, évitez les données personnelles et le contenu protégé par login, et préférez un flux officiel pour les volumes ou l'usage commercial.

Foire aux questions

Quelles données puis-je extraire d'une page de recherche Noon ?

Les champs publics de chaque carte de recherche : le titre du produit, le prix numérique, la devise, la note par étoiles lorsque l'article a des avis, la marque et le lien vers la page produit. Ce guide lit exactement ces champs depuis chaque span.productContainer de la grille. Tout ce qui se trouve derrière une connexion, comme les détails de compte ou l'historique des commandes, est hors du champ et n'est pas une donnée publique.

Pourquoi une requête simple retourne-t-elle des données incomplètes depuis Noon ?

Parce que Noon rend sa grille de produits côté client avec JavaScript et charge les cartes via AJAX, puis soumet le trafic automatisé à des CAPTCHAs. Une requête HTTP brute depuis une IP de centre de données retourne généralement une coquille vide ou une page de blocage plutôt que les cartes de produits. Pour obtenir une page complète, vous devez la rendre, attendre le contenu AJAX et la demander derrière une IP de confiance, ce que la Crawling API gère pour vous.

Que font ajax_wait et page_wait ?

Ils contrôlent le temps pendant lequel la Crawling API attend avant de capturer le HTML. Définir ajax_wait: 'true' maintient la requête jusqu'à ce que les téléchargements en arrière-plan se stabilisent, et page_wait ajoute un délai fixe en millisecondes pour que les cartes à chargement lent aient le temps de s'afficher. Les deux importent sur Noon car les données de produits arrivent après le chargement initial de la page, pas dans la première réponse.

Comment gérer la pagination sur Noon ?

Noon pagine sa recherche avec un paramètre de requête page, vous l'incrémentez donc et récupérez chaque page à tour de rôle. La fonction scrapeAllPages dans ce guide boucle de la page 1 jusqu'à une limite maxPages et s'arrête dès qu'une page retourne zéro produit, ce qui permet de détecter la fin des résultats sans deviner le nombre de pages à l'avance.

Mes sélecteurs retournent des valeurs vides. Qu'est-ce qui a changé ?

Presque certainement le balisage de Noon. Ses noms de classes hachés comme dGLdNc sont générés par le processus de construction et changent sans préavis, donc des sélecteurs qui fonctionnaient le mois dernier peuvent se casser. Réinspectez une page en direct dans les outils de développement de votre navigateur et mettez à jour le sélecteur, en préférant les attributs data-qa stables là où la page en propose un. La maintenance périodique des sélecteurs est normale pour tout scraper en production.

Puis-je extraire des données personnelles des clients depuis Noon ?

Non, et ce guide ne le couvre pas. Les détails de compte client, l'historique des commandes et tout ce qui se trouve derrière une connexion ne sont pas des données publiques. Scraper du contenu protégé par login, des données personnelles sur les évaluateurs au-delà du texte d'avis public, ou contourner l'authentification est hors du champ ici et va à l'encontre des conditions de Noon. Pour un accès sanctionné à grande échelle, un accord de données officiel est la bonne voie.

Commencer à construire

Crawlez n'importe quel site à grande échelle, sans combattre l'infrastructure.

Crawlbase gère les proxies, les empreintes et les CAPTCHA afin que votre équipe livre des pipelines de données au lieu de maintenir la plomberie de crawl. 1 000 requêtes gratuites, sans carte requise.

En libre-service · Sans appel commercial requis · Volumes de crawl entreprise disponibles