Product Hunt est l'endroit où de nouveaux logiciels, matériels et projets annexes sont lancés et classés chaque jour, et la face publique de ce classement est un signal clair pour quiconque suit ce que les créateurs publient. Les fondateurs l'observent pour évaluer leurs concurrents, les chercheurs l'utilisent pour repérer les tendances par catégorie, et les équipes de croissance étudient les lancements qui obtiennent le plus de votes. Les données sont là sur chaque page de catégorie : noms de produits, slogans, nombre de votes et lien vers chaque fiche.

Ce guide vous montre comment scraper Product Hunt avec JavaScript et Node.js en utilisant Cheerio. Vous créez un petit script fonctionnel qui récupère une page de catégorie Product Hunt via la Crawling API, analyse le nom du produit, le slogan, les votes et le lien pour chaque fiche, récupère optionnellement les informations publiques de base d'un profil de créateur, gère la pagination, et exporte le résultat en JSON et CSV. L'ensemble du tutoriel se limite aux données de produits publics, et la section sur la légalité vers la fin n'est pas un simple formulaire, donc lisez-la avant de pointer ce script sur un volume réel.

Ce que vous allez construire

Un script Node.js qui prend une URL de catégorie Product Hunt publique, récupère le HTML rendu via la Crawling API, et extrait un enregistrement structuré pour chaque produit de la liste. Nous utilisons la page de catégorie engineering and development comme exemple et extrayons ces champs par article :

  • Nom le nom du produit tel qu'affiché sur la carte de fiche.
  • Slogan la courte ligne de description sous le nom.
  • Votes le nombre de votes, converti en nombre quand il est présent.
  • Avis le texte du nombre d'avis, tel que "151 reviews".
  • Lien l'URL vers la page produit individuelle.

Plus loin dans le guide, nous ajoutons un passage séparé qui lit les champs publics de base d'un profil de créateur, comme le nom, le titre, les comptes d'abonnés et de suivis, et les points, pour vous montrer comment la même approche s'étend des fiches à un seul profil public.

Pourquoi une simple requête échoue sur Product Hunt

Si vous demandez une URL de catégorie Product Hunt avec un client HTTP basique, vous récupérez rarement la liste des produits. Deux facteurs jouent contre vous. Premièrement, Product Hunt rend ses cartes de fiches dans le navigateur avec JavaScript, donc le HTML initial est une coque presque vide jusqu'à ce que les scripts de la page s'exécutent. Deuxièmement, la plateforme surveille le trafic automatisé : les adresses IP de datacenter et les comportements de requête qui ne ressemblent pas à un vrai navigateur sont limités en débit ou bloqués avant d'atteindre les données produits rendues.

Un scraper Product Hunt fonctionnel a donc besoin de deux choses en une seule requête : un navigateur qui rend réellement la page, et une adresse IP que la plateforme perçoit comme un vrai visiteur. Vous pouvez assembler cela vous-même avec un navigateur sans interface graphique plus un pool de proxys résidentiels rotatifs, mais les assembler et les maintenir en bon état représente l'essentiel du travail. La Crawling API regroupe les deux en un seul appel : vous lui envoyez l'URL, elle rend la page derrière une IP fiable, et vous renvoie du HTML prêt à analyser avec Cheerio.

Pourquoi le token JavaScript

Parce que Product Hunt construit ses fiches côté client, vous demandez ces pages avec le rendu JavaScript de la Crawling API activé. Dans le client Node officiel, cela signifie l'initialiser avec votre token JavaScript. Les requêtes rendues coûtent plus de crédits que les requêtes simples, donc le niveau gratuit vous permet quand même de tester l'ensemble du flux avant de monter en charge.

Prérequis

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

JavaScript et Node.js de base. Vous devez être à l'aise avec l'écriture et l'exécution d'un script Node, l'installation de paquets avec npm, et la maîtrise des concepts DOM que Cheerio reproduit. Si vous êtes nouveau avec Node, le guide pour créer un scraper web avec Node.js couvre les bases que ce tutoriel suppose acquises.

Node.js 16 ou ultérieur. Confirmez votre version avec node --version. Si vous ne l'avez pas, installez-le depuis le site 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 JavaScript depuis la page de documentation du compte. Le niveau gratuit vous donne jusqu'à 20 000 requêtes sans carte. Traitez le token comme un mot de passe : il authentifie vos requêtes, donc gardez-le hors du contrôle de version.

Configurer le projet

Créez un dossier de projet, initialisez-le, et installez les deux bibliothèques nécessaires au scraper.

bash
node --version

mkdir producthunt-scraper && cd producthunt-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 pour extraire les champs individuels par sélecteur CSS. Créez un fichier nommé scraper.js dans ce dossier et ajoutez le code des étapes ci-dessous.

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

Commencez par obtenir la page complète. Importez la classe CrawlingAPI, initialisez-la avec votre token JavaScript, et demandez l'URL de catégorie. Sauvegarder le corps sur disque vous permet d'inspecter le vrai balisage une fois, puis d'itérer sur les sélecteurs sans dépenser une requête à chaque fois.

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

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

const producthuntPageURL =
  'https://www.producthunt.com/categories/engineering-development';

api
  .get(producthuntPageURL)
  .then((response) => {
    if (response.statusCode === 200) {
      fs.writeFileSync('response.html', response.body);
      console.log('HTML saved to response.html');
    }
  })
  .catch((error) => console.error('API request error:', error));

Exécutez le script avec node scraper.js et vous devriez voir du vrai balisage Product Hunt écrit dans response.html, pas une coque simplifiée. Cela confirme que le rendu fonctionne avant que vous n'écriviez un seul sélecteur. Remplacez l'URL d'exemple par n'importe quelle page de catégorie que vous voulez ; toutes les catégories sont sous /categories/ sur le même domaine.

Crawlbase Crawling API

Cette première requête vient de retourner une page de catégorie Product Hunt entièrement rendue sans navigateur sans interface graphique ni proxy de votre côté. La Crawling API exécute la page dans un vrai navigateur, fait tourner les IP résidentielles côté serveur, et gère les limites de débit que la plateforme impose aux scrapers, pour que vous obteniez du HTML finalisé en un seul appel. Pointez-la sur la catégorie engineering and development sur le niveau gratuit d'abord.

Étape 2 : Analyser chaque produit avec Cheerio

Avec le HTML rendu en main, chargez-le dans Cheerio et parcourez les cartes produits. Product Hunt dispose chaque fiche dans un conteneur répété, donc vous sélectionnez chaque carte, puis lisez le nom, le slogan, les votes, les avis et le lien depuis l'intérieur. Lire chaque champ de façon défensive empêche une seule valeur manquante de faire planter l'exécution.

javascript
const fs = require('fs');
const cheerio = require('cheerio');

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

  const containers = $(
    'div.flex.direction-column.mb-mobile-10.mb-tablet-15.mb-desktop-15.mb-widescreen-15'
  );

  containers.each((index, element) => {
    const card = $(element);

    const name = card
      .find('div.color-blue.fontSize-18.fontWeight-600')
      .text()
      .trim();

    // Each filled star is one label element inside the rating row
    const upvotes = card.find(
      'div.flex.direction-row.align-center label'
    ).length;

    const reviews = card
      .find('div.ml-3.color-lighter-grey.fontSize-14.fontWeight-400')
      .text()
      .trim();

    const tagline = card
      .find(
        'div.color-lighter-grey.fontSize-mobile-14.fontSize-tablet-16.fontSize-desktop-16.fontSize-widescreen-16.fontWeight-400'
      )
      .text()
      .trim();

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

    if (name) {
      products.push({ rank: index + 1, name, tagline, upvotes, reviews, link });
    }
  });

  return products;
}

Quelques détails maintiennent cette extraction fidèle à la page. Le nom du produit provient du bloc color-blue fontSize-18 fontWeight-600, et le slogan de la longue chaîne de classes de taille de police color-lighter-grey que Product Hunt utilise pour la ligne de description. La ligne de votes et d'évaluation rend un élément label par marqueur rempli, donc compter ces éléments label vous donne le compte sans analyser aucun texte. Le texte du nombre d'avis se trouve dans son propre bloc ml-3 color-lighter-grey, et le lien est lu depuis le premier ancre de la carte et résolu en URL absolue pour fonctionner en dehors de la page.

Les sélecteurs dérivent

Les noms de classes de Product Hunt (les longues chaînes fontSize-* et le reste) sont générés et changent sans préavis. Traitez les sélecteurs ci-dessus comme un modèle de départ, pas comme un contrat. Quand 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. La maintenance périodique des sélecteurs est normale pour tout scraper en production, pas le signe que quelque chose est cassé. Pour la technique plus large, consultez comment crawler des sites JavaScript.

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

Reliez maintenant la récupération et l'analyse en un seul script exécutable, puis écrivez les enregistrements sur disque en JSON et CSV.

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

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

async function crawl(pageUrl) {
  const response = await api.get(pageUrl);
  if (response.statusCode === 200) return response.body;
  console.error(`Request failed: ${response.statusCode}`);
  return null;
}

function toCsv(rows) {
  const headers = ['rank', 'name', 'tagline', 'upvotes', 'reviews', '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 url =
    'https://www.producthunt.com/categories/engineering-development';
  const html = await crawl(url);
  if (!html) return;

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

main();

Collez la fonction parseProducts de l'Étape 2 dans le même fichier pour que main puisse l'appeler. Exécutez avec node scraper.js et vous obtenez deux fichiers : products.json avec les enregistrements structurés complets et products.csv prêt à ouvrir dans un tableur. L'utilitaire toCsv met entre guillemets chaque champ et double les guillemets intégrés, ce qui est important ici car les slogans de produits sont longs et contiennent fréquemment des virgules.

À quoi ressemble le résultat

Le fichier JSON contient un objet par produit dans l'ordre de la fiche, chacun avec le rang, le nom, le slogan, le nombre de votes, le texte du nombre d'avis et le lien.

json
[
  {
    "rank": 1,
    "name": "The Free Website Guys",
    "tagline": "A free website program that has helped over 10,000 entrepreneurs.",
    "upvotes": 5,
    "reviews": "151 reviews",
    "link": "https://www.producthunt.com/products/the-free-website-guys"
  },
  {
    "rank": 2,
    "name": "Zipy",
    "tagline": "A debugging platform with session replay and network monitoring.",
    "upvotes": 5,
    "reviews": "132 reviews",
    "link": "https://www.producthunt.com/products/zipy"
  }
]

Le CSV reflète les mêmes lignes avec une ligne d'en-tête, donc il s'intègre directement dans Excel, Google Sheets ou tout pipeline de données qui lit les fichiers délimités.

csv
rank,name,tagline,upvotes,reviews,link
"1","The Free Website Guys","A free website program that has helped over 10,000 entrepreneurs.","5","151 reviews","https://www.producthunt.com/products/the-free-website-guys"
"2","Zipy","A debugging platform with session replay and network monitoring.","5","132 reviews","https://www.producthunt.com/products/zipy"

Gérer la pagination à travers la catégorie

Une page est une démonstration ; un vrai travail parcourt toute la catégorie. Product Hunt charge davantage de fiches à mesure que vous faites défiler, et les pages de catégorie acceptent aussi un paramètre de page que vous pouvez parcourir étape par étape. Le modèle le plus simple et fiable est de récupérer des pages successives, d'analyser chacune avec la même fonction, et de s'arrêter quand une page ne renvoie aucun nouveau produit. Cadencer la boucle avec un court délai maintient votre taux de requêtes calme.

javascript
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

async function scrapeCategory(slug, maxPages = 5) {
  const all = [];
  for (let page = 1; page <= maxPages; page++) {
    const url =
      `https://www.producthunt.com/categories/${slug}?page=${page}`;
    const html = await crawl(url);
    if (!html) break;

    const rows = parseProducts(html);
    if (rows.length === 0) break;

    all.push(...rows.map((p) => ({ category: slug, ...p })));
    await sleep(2000);
  }
  return all;
}

scrapeCategory('engineering-development').then((rows) => {
  console.log(`Collected ${rows.length} products`);
});

Parce que chaque page de catégorie partage la même structure de carte, le parseur que vous avez déjà écrit fonctionne sur toutes sans modification. Taguez chaque ligne avec sa catégorie avant l'export et vous pouvez comparer ce qui est publié dans, par exemple, engineering, design et IA dans un seul jeu de données. Ce modèle s'applique directement à la recherche produits ; pour une analyse approfondie sur la façon de transformer les fiches classées en décisions, consultez comment automatiser la recherche produits e-commerce.

Scraper les données publiques de profil de base

La même approche récupération-puis-analyse fonctionne sur un seul profil public de créateur. Les profils exposent des champs publics de base tels qu'un nom d'affichage, un titre, les comptes d'abonnés et de suivis, des points, et les produits qu'un créateur a publiés. L'ancienne version de ce guide lisait ces données depuis la page de profil ; l'extrait ci-dessous porte les mêmes champs. Limitez-vous à ces bases de profil public uniquement, et lisez la section légalité avant de l'exécuter.

javascript
function parseProfile(html, handle) {
  const $ = cheerio.load(html);
  const profile = {};

  profile.name = $(
    'h1.color-darker-grey.fontSize-24.fontWeight-600'
  ).text().trim();
  profile.headline = $(
    'div.color-lighter-grey.fontSize-18.fontWeight-300'
  ).text().trim();
  profile.followers = $(
    `a[href="/@${handle}/followers"]`
  ).text().trim();
  profile.following = $(
    `a[href="/@${handle}/following"]`
  ).text().replace(/\n\s+/g, ' ').trim();
  profile.points = $(
    'span.color-lighter-grey.fontSize-14.fontWeight-400:contains("points")'
  ).text().trim();

  // Public list of products the maker has shipped
  profile.products = [];
  $('.styles_even__Qeyum, .styles_odd__wazk7').each((i, el) => {
    profile.products.push({
      name: $(el).find('img.styles_thumbnail__Y9ZpZ').attr('alt'),
    });
  });

  return profile;
}

async function scrapeProfile(handle) {
  const html = await crawl(`https://www.producthunt.com/@${handle}`);
  return html ? parseProfile(html, handle) : null;
}

Les sélecteurs reflètent les champs de l'ancienne version : le nom d'affichage depuis l'en-tête h1.color-darker-grey, le titre depuis la ligne fontSize-18 fontWeight-300, les comptes d'abonnés et de suivis depuis les ancres qui renvoient vers les propres pages d'abonnés et de suivis de l'identifiant, et le total des points depuis le span qui contient le mot "points". La liste des produits lit le texte alt de chaque miniature. Limitez-vous à ces bases publiques uniquement, et n'allez pas plus loin dans tout ce qui identifie un individu privé.

Rester non bloqué

Même avec le rendu pris en charge, Product Hunt surveille le trafic à l'allure d'un scraper. Quelques bonnes habitudes maintiennent une exécution en bonne santé, et elles s'appliquent à toute cible commerciale.

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

Pour le guide complet, consultez comment scraper des sites web sans être bloqué.

Est-il légal de scraper Product Hunt ?

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

Quelques lignes à respecter. Collectez uniquement les données publiques de produits : les noms, slogans, nombres de votes, nombres d'avis et liens que n'importe qui peut voir sur une page de catégorie sans compte. Ne collectez pas de données personnelles sur les créateurs au-delà des bases de profil public affichées sur la page, et n'assemblez jamais des profils dans un jeu de données qui cible ou identifie des individus privés. Respectez les attentes déclarées de Product Hunt en matière de débit et maintenez votre volume de requêtes suffisamment bas pour ne pas solliciter excessivement ses serveurs. Ne redistribuez pas les médias protégés par des droits d'auteur de Product Hunt, comme les images de produits ou les avatars de créateurs, comme s'ils étaient les vôtres. Si vous prévoyez de réutiliser les données commercialement, obtenez une autorisation ou un accord officiel plutôt que de supposer que le silence vaut consentement.

Pour un volume ou un usage commercial, Product Hunt dispose d'une API officielle. Elle utilise l'authentification par token OAuth2 et applique ses propres limites de débit, et l'usage commercial est restreint par défaut, donc vous contactez Product Hunt pour approbation avant de construire une activité dessus. Cette API officielle est le bon outil quand vous avez besoin de gros volumes, d'une structure garantie ou de droits commerciaux. Ce guide est délibérément limité aux fiches publiques et aux bases de profil public car c'est la ligne qui rend le travail défendable. Il ne couvre rien derrière une connexion, les données utilisateurs privées, ni aucune tentative de contournement de l'authentification. Si votre projet nécessite plus que des données publiques, l'API Product Hunt officielle ou un accord de données est la bonne voie, pas un scraper plus sophistiqué.

Récapitulatif

Points clés

  • Product Hunt rend les fiches côté client. Une requête simple renvoie une coque vide, donc vous devez rendre la page derrière une IP fiable avant de l'analyser.
  • La Crawling API fait les deux en un seul appel. Elle rend la page avec le token JavaScript, fait tourner les IP résidentielles, et renvoie du HTML finalisé à analyser avec Cheerio.
  • Cheerio extrait les champs. Sélectionnez chaque conteneur de produit, puis lisez le nom, le slogan, les votes, les avis et le lien, en dérivant le rang depuis l'index de boucle, et attendez-vous à ce que les noms de classes générés dérivent.
  • Paginez et exportez. Parcourez les pages de catégorie jusqu'à ce que l'une revienne vide, puis écrivez les enregistrements structurés en JSON et CSV, en mettant entre guillemets les champs CSV pour que les slogans à virgules restent intacts.
  • Restez sur les données publiques. Respectez les CGU et le robots.txt de Product Hunt, prenez uniquement les bases de profil public, jamais de données personnelles, et préférez l'API Product Hunt officielle pour un volume ou un usage commercial.

Foire aux questions

Quelles données puis-je scraper de Product Hunt ?

Depuis une page de catégorie publique, vous pouvez extraire le nom, le slogan, le nombre de votes, le texte du nombre d'avis et le lien vers la fiche de chaque produit. Depuis un profil public de créateur, vous pouvez lire les champs publics de base tels que le nom d'affichage, le titre, les comptes d'abonnés et de suivis, les points, et les produits que ce créateur a publiés. Limitez la collecte à ces bases publiques et évitez tout ce qui identifie un individu privé au-delà de ce que la page affiche ouvertement.

Pourquoi une requête simple renvoie-t-elle des données incomplètes de Product Hunt ?

Parce que Product Hunt rend ses fiches côté client avec JavaScript et surveille le trafic automatisé. Une requête HTTP brute depuis une IP de datacenter renvoie généralement une coque presque vide plutôt que les cartes produits. Pour obtenir une page complète, vous devez la rendre derrière une IP fiable, ce que la Crawling API gère pour vous quand vous utilisez son token JavaScript.

Ai-je besoin du token JavaScript pour Product Hunt ?

Oui. Product Hunt construit ses pages de catégorie et de profil dans le navigateur, donc vous les demandez avec le rendu JavaScript activé, ce qui dans le client Node officiel signifie initialiser la Crawling API avec votre token JavaScript. Les requêtes rendues coûtent plus de crédits que les requêtes simples, mais le niveau gratuit vous permet quand même de tester l'ensemble du flux avant de monter en charge.

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

Presque certainement le balisage de Product Hunt. Ses noms de classes générés, les longues chaînes fontSize-* et les classes hachées styles_*, 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 les sélecteurs. La maintenance périodique des sélecteurs est normale pour tout scraper en production.

Existe-t-il une API Product Hunt officielle ?

Oui. Product Hunt propose une API officielle qui utilise l'authentification par token OAuth2 et applique des limites de débit, avec l'usage commercial restreint par défaut, donc vous demandez l'approbation avant de l'utiliser à des fins commerciales. Quand vous avez besoin de gros volumes, d'une structure garantie ou de droits commerciaux, l'API officielle est la bonne voie plutôt que le scraping.

Comment éviter d'être bloqué lors du scraping de Product Hunt ?

Maintenez votre taux de requêtes par IP bas, ajoutez des délais entre les récupérations de pages, et acheminez via des IP résidentielles rotatives pour qu'aucune adresse unique ne déclenche une limite de débit. La Crawling API gère la rotation et un pool d'IP fiables pour vous ; si vous construisez votre propre infrastructure, c'est la partie dans laquelle investir. Surveillez les codes de statut et reculez quand vous commencez à voir des défis.

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