Retour au Centre de connaissances
Démarrage

Scraping avec Puppeteer : options et observations

Distinguer lancement, viewport, stockage et mode headless de Puppeteer avec les valeurs observables sur un catalogue dont vous êtes propriétaire.

BotBrowser Team

Scraping avec Puppeteer : options et observations
Documentation

Vous voulez la documentation structurée pour Démarrage ?

Cet article fait partie de la bibliothèque éditoriale. Pour les étapes de configuration, la référence et les mises à jour continues, passez directement à la section docs.

BotBrowser documente un lancement Puppeteer avec profil utilisant puppeteer-core, executablePath, defaultViewport et --bot-profile ; il ne garantit pas une réponse tierce ni un résultat de détection.

Résumé

Les réglages de scraping avec Puppeteer ont des portées distinctes. executablePath, headless et userDataDir concernent le processus ; defaultViewport, l'émulation de la page ; BrowserContext, le stockage géré par le navigateur dans ce processus. Une page lit des dimensions ou navigator.webdriver, mais ces observations ne constituent ni verdict, ni preuve d'identité, ni autorisation.

Sur un catalogue vous appartenant, fixez binaire et profil, modifiez une option et conservez URL finale, dimensions, navigator.webdriver, nombre de lignes acceptées et diagnostics. Cette comparaison réfutable ne prouve pas qu'un mode est mieux accepté ou protège davantage la vie privée.

Sommaire

Options du processus

L'intégration de lancement Puppeteer couvre l'installation du paquet et la connexion initiale avec profil ; la comparaison suivante suppose cette intégration déjà configurée.

executablePath désigne l'exécutable à lancer. L'existence du chemin ne prouve ni le chargement de la version attendue, ni l'acceptation du profil, ni la réponse d'un site. Conservez chemin, version du paquet, version de l'exécutable et arguments pour identifier une entrée de processus modifiée.

Trois valeurs de headless sont documentées : true utilise le mode headless actuel de Chrome, 'shell' le binaire séparé chrome-headless-shell, et false un navigateur avec interface. Processus, rendu et fonctions d'interface peuvent différer. Ce sont des choix d'exécution, sans valeur de confiance, d'acceptation ou de droit d'accès. Une page de référence produit des valeurs, pas une décision du serveur.

userDataDir est le répertoire des données persistantes du processus. Ce n'est ni le fichier de profil .enc de BotBrowser ni un BrowserContext. Donnez aux processus concurrents des répertoires accessibles en écriture distincts. Réutiliser un répertoire peut conserver cookies et stockage local, mais partage aussi l'état entre exécutions : indiquez-le explicitement.

La configuration Puppeteer de BotBrowser documente puppeteer-core, le mode Chrome, executablePath, defaultViewport: null et --bot-profile. La référence des profils décrit les valeurs du profil. Aucun de ces documents ne promet une réponse du site ni un verdict tiers.

Portée des options Puppeteer du processus à la page puis au relevé JSON

Portée de la page et du contexte

Puppeteer applique un viewport par défaut de 800 sur 600 via les options de page. defaultViewport: null supprime cette émulation par défaut sans établir la taille de l'écran du système, l'état du gestionnaire de fenêtres ou les dimensions physiques du moniteur. Relevez window.innerWidth, window.innerHeight, screen.width et screen.height.

Un BrowserContext isole cookies et stockage des autres contextes du même processus. Il ne sélectionne pas un autre exécutable, ne crée pas d'IP publique, n'accorde pas de permission de collecte et n'établit pas d'identité. Identifiant de contexte et politique de stockage décrivent des entrées, pas une preuve d'accès.

Le booléen en lecture seule navigator.webdriver est visible par la page. MDN décrit les conditions où Chrome contrôlé par automatisation l'expose. true ou false peut expliquer une différence ; un détecteur dispose d'autres signaux et un serveur de données inconnues de la page. L'analyse des limites des correctifs Puppeteer et Playwright distingue modification JavaScript et comportement non contrôlé par un correctif.

Séparez installation et exécution. La configuration de Puppeteer règle téléchargements et cache ; puppeteer-core ignore ces fichiers. Un cache modifié peut changer le binaire installé, mais ne représente pas une observation du viewport ou du stockage. Conservez exécutable résolu et versions des paquets.

Champs du relevé

Avant le lancement, créez un relevé : identifiant, version du paquet, exécutable résolu, chaîne de version, nom d'argument du profil sans octets secrets, mode headless, viewport, révision du catalogue et origine propre. Ces champs déterminent si deux JSON sont comparables. Excluez cookies, jetons, contenu du profil et chaînes de requête authentifiées.

Options et observations

EntréePortéeObservations et diagnostics à conserverCe qui ne peut pas être établi
executablePathProcessusVersion et API disponiblesChargement du binaire demandé ou acceptation du serveur
headlessProcessusViewport, rendu, propriétés sélectionnéesConfiance, autorisation ou verdict
defaultViewportÉmulation de pageinnerWidth, innerHeight, valeurs d'écranDimensions physiques du moniteur
userDataDirÉtat persistantCookies et stockage disponiblesProfil, IP publique ou propriété du compte
BrowserContextStockage du contexteCookies locaux et isolationNouveau binaire, identité réseau ou permission
navigator.webdriverChamp de pageBooléen en lecture seuleEmpreinte complète ou décision du serveur

Acceptation du catalogue

Vérifiez une origine HTTP ou HTTPS appartenant au projet, terminée par /, sans identifiants, requête ni fragment. La route doit rester sur cette origine après navigation. Chaque ligne contient exactement un nom et un prix au format décimal déclaré. Refusez doublons, liens vers une autre origine, devise absente et chemins inattendus.

Reproductibilité et fermeture

Utilisez un nouveau RUN_USER_DATA_DIR par comparaison indépendante, sauf si la persistance est la variable étudiée. Fixez le profil et copiez uniquement des données autorisées. Borner la navigation et distinguer délai dépassé avant ou après réponse permet de décrire transport ou disponibilité, sans conclure au rejet du navigateur.

Manifeste des entrées

Conservez avec le relevé version de Puppeteer, empreinte du verrouillage des paquets, version de l'exécutable, mode, viewport, politique de contexte, révision du catalogue et heure de départ. Un chemin ne suffit pas : un exécutable peut être remplacé et un répertoire conserver un état antérieur. Le manifeste fixe les entrées sans copier profils ni comptes.

Préservez les types : headless vaut true, false ou 'shell' ; defaultViewport vaut null ou un objet aux dimensions numériques. Représentez userDataDir par un identifiant expurgé plutôt qu'un chemin privé. Une variable d'environnement exige nom et valeur résolue. N'assimilez pas option omise et valeur explicite avant d'avoir noté la version de Puppeteer.

Conservez URL demandée, URL finale, nombre de redirections, état HTTP et durée jusqu'à domcontentloaded. Ces champs répondent à des questions distinctes : une page de la même origine peut signaler une erreur et un 200 peut échouer au schéma. Un délai avant la première réponse diffère d'un délai pendant un script. Séparez transport, navigation et données.

Le catalogue doit fournir un signal déterministe de disponibilité. Deux lignes fixes sont plus comparables qu'une liste qui grandit pendant sa lecture. Attendez le marqueur puis vérifiez le nombre de lignes. Une absence de trafic ne prouve pas la fin de l'application : analytique, interrogations périodiques et Service Workers peuvent continuer ; une page d'erreur peut être immédiatement silencieuse.

Validation des données

Validez avant écriture : un nom, un prix et une devise de trois lettres par ligne. Si du texte brut est nécessaire au diagnostic, conservez-le localement avec protection ; le relevé partagé peut contenir une empreinte expurgée et le résultat. Deux lignes acceptées et zéro ligne ne sont pas équivalents, sans rien démontrer pour d'autres routes ou services.

Nommez champ et règle : price-format, currency-code, duplicate-item et missing-name renseignent davantage que schema=false. Ajoutez révision des sélecteurs et empreinte du catalogue : un changement de balisage peut échouer sans modification des entrées du navigateur.

Calcul des différences

Une fois les deux relevés présents, triez les identifiants par clé, normalisez les barres finales et comparez les dimensions comme nombres. Séparez les champs non observés. Ce format hypothétique ne contient pas de résultats mesurés :

{
  "changedOption": "defaultViewport",
  "before": { "innerWidth": 800, "innerHeight": 600 },
  "after": { "innerWidth": 1280, "innerHeight": 720 },
  "same": ["origin", "itemCount", "currency"],
  "changed": ["innerWidth", "innerHeight"],
  "notObserved": ["screenX"],
  "interpretation": "The fixture read a different emulated viewport."
}

L'interprétation nomme observation et portée, sans conclusion sur personne, détecteur, propriétaire du profil ou politique du site. Si version de l'exécutable ou du catalogue diffère, marquez not-comparable avant d'interpréter. Deux entrées modifiées constituent une autre expérience.

Comparaisons de persistance

Pour étudier la persistance, ne changez que cette variable. A démarre avec un répertoire neuf ; fermez le navigateur puis réutilisez ce répertoire pour B. Notez les clés signalées par le catalogue propre, jamais les valeurs de cookies ou jetons. Une troisième exécution sur répertoire neuf peut confirmer une dépendance à la persistance, pas la propriété du compte ou l'autorisation.

L'isolation des contextes se compare séparément : deux contextes dans un processus chargent la même origine ; notez si chacun lit le marqueur. Fermez-les et recommencez dans un nouveau processus si la réutilisation importe. Cela décrit le stockage du catalogue, sans changement implicite du binaire, du réseau ou de la décision serveur.

Versions et retour arrière

Fixez paquet et exécutable durant la comparaison. Une version modifiée exige une nouvelle paire de relevés même si les options restent identiques. Une mise à jour peut changer rendu, valeurs par défaut ou champs exposés. Conservez la différence précédente et le motif d'adoption de la nouvelle version.

Un retour arrière restaure verrouillage des paquets, exécutable, référence du profil, arguments, viewport, politique de contexte et catalogue. Restaurer seulement headless ou defaultViewport ne reproduit pas un relevé avec un autre binaire ou stockage. Versionnez catalogue et verrouillage ; séparez références de profil et contenu secret.

Exemple borné à une variable

La page propre expose deux lignes data-testid="item" à /catalog, chacune avec data-id unique, nom, prix et devise. Le catalogue définit data-ready="true" sur data-testid="catalog" seulement après leur achèvement. Le script est illustratif, sans exécution revendiquée ; il écrit après validation de la réponse, de l'URL, de la disponibilité et des lignes.

import puppeteer from 'puppeteer-core';
import fs from 'node:fs/promises';

const origin = new URL(process.env.OWNED_CATALOG_ORIGIN ?? '');
const executablePath = process.env.BOTBROWSER_EXEC_PATH;
const profilePath = process.env.BOT_PROFILE_PATH;
const mode = process.env.HEADLESS_MODE ?? 'true';
const viewportMode = process.env.DEFAULT_VIEWPORT ?? '800x600';
if (
  !['http:', 'https:'].includes(origin.protocol) ||
  origin.username ||
  origin.password ||
  origin.pathname !== '/' ||
  origin.search ||
  origin.hash
)
  throw new Error('OWNED_CATALOG_ORIGIN must be a plain HTTP(S) origin');
if (!['true', 'false'].includes(mode)) throw new Error('HEADLESS_MODE must be true or false');
if (!['null', '800x600'].includes(viewportMode)) throw new Error('invalid DEFAULT_VIEWPORT');
if (!executablePath || !profilePath || !process.env.RUN_USER_DATA_DIR)
  throw new Error('browser inputs and a dedicated RUN_USER_DATA_DIR are required');
const viewport = viewportMode === 'null' ? null : { width: 800, height: 600 };
const headless = mode === 'true';
const browser = await puppeteer.launch({
  browser: 'chrome',
  executablePath,
  headless,
  defaultViewport: viewport,
  args: [`--bot-profile=${profilePath}`],
  userDataDir: process.env.RUN_USER_DATA_DIR,
});
const diagnostics = [];
try {
  const context = await browser.createBrowserContext();
  const page = await context.newPage();
  const assertRoute = () => {
    const url = new URL(page.url());
    if (url.origin !== origin.origin || url.pathname !== '/catalog' || url.search || url.hash)
      throw new Error('unexpected catalogue URL');
  };
  const started = Date.now();
  const response = await page.goto(new URL('catalog', origin).href, {
    waitUntil: 'domcontentloaded',
    timeout: 15000,
  });
  assertRoute();
  if (!response || !response.ok()) throw new Error(`HTTP response rejected: ${response?.status()}`);
  const navigationMs = Date.now() - started;
  await page.waitForSelector('[data-testid="catalog"][data-ready="true"]', { timeout: 5000 });
  const items = await page.$$eval('[data-testid="item"]', nodes =>
    nodes.map(node => {
      if (
        node.querySelectorAll('[data-testid="item-name"]').length !== 1 ||
        node.querySelectorAll('[data-testid="item-price"]').length !== 1
      )
        throw new Error('name or price cardinality rejected');
      return {
        id: node.getAttribute('data-id'),
        name: node.querySelector('[data-testid="item-name"]')?.textContent?.trim(),
        price: node.querySelector('[data-testid="item-price"]')?.textContent?.trim(),
        currency: node.querySelector('[data-testid="item-price"]')?.getAttribute('data-currency'),
      };
    })
  );
  if (
    items.length !== 2 ||
    new Set(items.map(item => item.id)).size !== 2 ||
    items.some(
      item =>
        !item.id || !item.name || !/^\d+\.\d{2}$/.test(item.price ?? '') || !/^[A-Z]{3}$/.test(item.currency ?? '')
    )
  )
    throw new Error('fixture row schema rejected');
  const observed = await page.evaluate(() => ({
    innerWidth: window.innerWidth,
    innerHeight: window.innerHeight,
    screenWidth: screen.width,
    screenHeight: screen.height,
    webdriver: navigator.webdriver,
  }));
  assertRoute();
  diagnostics.push({
    finalUrl: page.url(),
    status: response.status(),
    navigationMs,
    redirectCount: response.request().redirectChain().length,
    itemCount: items.length,
  });
  await fs.writeFile(
    'puppeteer-scrape-record.json',
    JSON.stringify(
      {
        inputs: { headless, defaultViewport: viewport },
        controls: { userDataPolicy: 'fresh-empty-per-run', contextPolicy: 'new-isolated-context' },
        observed,
        items,
        diagnostics,
      },
      null,
      2
    ),
    { flag: 'wx' }
  );
} finally {
  await browser.close();
}

Fixez origine, exécutable, profil, catalogue, verrouillage et sélecteurs entre A et B. Changez uniquement l'option étudiée, HEADLESS_MODE ou DEFAULT_VIEWPORT. Chaque processus utilise un RUN_USER_DATA_DIR distinct, initialement vide : les chemins diffèrent mais la politique reste fresh-empty-per-run. Toutes les entrées brutes ne sont donc pas identiques. Vérifiez cette politique avant le lancement. Le script compare headless ou viewport, pas la persistance.

L'exemple accepte seulement true et false pour HEADLESS_MODE : headless-shell changerait aussi le binaire. Chaque invocation emploie un répertoire de sortie distinct car flag: 'wx' interdit l'écrasement. Vérifiez qu'une seule valeur inputs diffère et que les deux politiques de contrôle correspondent avant d'attribuer changedOption.

Le script écrit uniquement un relevé de réussite. Conservez séparément le manifeste : il ne déduit pas les identifiants du paquet, de l'exécutable, du profil, du catalogue ou des sélecteurs. Pour les échecs, gardez code de sortie et erreur, puis classez l'étape selon les catégories suivantes. Ni JSON absent ni JSON ancien ne prouve la réussite actuelle. Un échec de lancement, navigation, disponibilité ou schéma reste une invocation échouée.

Le nouveau contexte démarre avec stockage isolé : userDataDir persistant ne lui transmet pas les cookies du contexte par défaut. Une comparaison de persistance utilise ce dernier de façon constante ou établit explicitement le même état dans chaque contexte nouveau. La référence des contextes, pages et fermeture décrit leur propriété. Fermer le navigateur ferme aussi pages et contextes, même si la création de page ou la validation échoue.

Portée et limites des observations

Chaque champ a une portée : viewport pour l'émulation, userDataDir pour la persistance, headless pour le mode du processus, navigator.webdriver pour un booléen. Aucun ne constitue une empreinte complète ni n'identifie seul personne, appareil, propriétaire ou verdict.

Distinguez same, changed et not-observed. Un champ absent n'est pas false : API indisponible, permission refusée ou champ absent du catalogue sont possibles. Séparez HTTP et données métier acceptées. Un 200 peut contenir un catalogue vide ou invalide ; un relevé valide ne garantit aucune autre route.

Avant d'interpréter, comparez exécutable résolu, version de Puppeteer, arguments, répertoire, création du contexte, URL, état HTTP, révision du catalogue et empreinte des sélecteurs. Un binaire changé, des cookies anciens ou un catalogue modifié ne deviennent pas ainsi des effets du viewport.

Catégories de défaillance

executablePath invalide : démarrage ; profil absent : entrée de lancement ; userDataDir partagé : isolation ; URL hors origine : autorisation ou navigation ; 200 avec zéro ligne acceptée : schéma. Conservez ces catégories au lieu de relancer toutes les erreurs avec la même commande.

Si puppeteer-core ignore une configuration attendue, examinez arguments explicites et binaire résolu. Si defaultViewport: null donne des dimensions inattendues, relevez les quatre dimensions et l'environnement d'affichage sans déduire le moniteur physique. Si navigator.webdriver diffère, notez mode et arguments sans modifier la propriété.

Questions fréquentes

Que change le mode headless ?

Il sélectionne un mode d'exécution. La page observe certaines conséquences ; le serveur peut utiliser d'autres signaux. Le relevé décrit des différences sans promettre résultat de détection ou réponse du site.

userDataDir est-il un fichier de profil ?

Non, c'est un répertoire de données persistantes. Entrée de profil et répertoire ont des durées de vie et propriétaires distincts ; notez les deux.

Un nouveau BrowserContext crée-t-il une identité ?

Non. Il isole des données de session dans le navigateur, sans accorder d'autorisation, changer l'IP publique ou établir la propriété de la session.

Pourquoi relever navigator.webdriver ?

Ce champ visible peut expliquer une différence du catalogue. Il n'est pas un verdict et ne doit pas être supprimé ou réécrit pour ce diagnostic.

Sources

Conclusion pratique

Modifiez une option de lancement ou de page en fixant catalogue propre, exécutable, profil, politique de contexte, versions et sélecteurs. Conservez observations et diagnostics exacts, classez les erreurs par portée et laissez les inconnues inconnues. La différence explique ce que la page lit, sans prouver absence de détection, identité du profil ou acceptation obligatoire du site.

Lectures : contextes, pages et fermeture Puppeteer et limites des correctifs Puppeteer et Playwright.

#Puppeteer#scraping web#Browser Automation#signaux du navigateur

Cet article fait partie du guide : Débuter avec l'automatisation du navigateur : carte initiale

Exécutez la même vérification dans BotBrowser

Chargez un profil, gardez dans le navigateur les signaux que vous venez de lire, puis confirmez le résultat sur votre propre machine avant le déploiement.