chromedp en revue : un vrai navigateur a toujours besoin de la bonne condition de disponibilité

Dernière mise à jour le August 17, 2026
chromedp en revue : un vrai navigateur a toujours besoin de la bonne condition de disponibilité
Résumé IA
chromedp est une bibliothèque pure Go, sous licence MIT, qui pilote un vrai Chrome via le Chrome DevTools Protocol. Elle lit le DOM après l’exécution du JavaScript de la page depuis un programme Go, sans WebDriver séparé ni runtime Node. Le module Go s’intègre à l’application, mais le système exécutable requiert toujours un binaire Chrome externe, dont le cycle de vie est géré via les contextes Go. L’installation s’est résumée à un simple go get plus un Chrome que j’ai dû fournir moi-même : créer un allocator, dériver un contexte, puis passer à Run une liste d’actions.

chromedp est une bibliothèque pure Go, sous licence MIT, qui pilote un vrai Chrome via le Chrome DevTools Protocol. Elle lit le DOM après l’exécution du JavaScript de la page depuis un programme Go, sans WebDriver séparé ni runtime Node. Le module Go s’intègre à l’application, mais le système exécutable requiert toujours un binaire Chrome externe, dont le cycle de vie est géré via les contextes Go.

L’installation s’est résumée à un simple go get plus un Chrome que j’ai dû fournir moi-même : créer un allocator, dériver un contexte, puis passer à Run une liste d’actions. Sur cet hôte macOS arm64 avec un headless shell déjà chaud sur disque, un nouveau processus jusqu’au premier résultat de script affichait une médiane de 102 ms. Il s’agit d’une base locale, pas d’une affirmation générale selon laquelle le démarrage n’est jamais un goulot d’étranglement. Sur un jeu de test qui injecte un lien 800 millisecondes après le chargement, deux des quatre stratégies de lecture ont répondu avant que le lien n’existe.

Le navigateur était bien réel, le contenu était bien là, et le code n’attendait tout simplement pas assez longtemps. C’est la leçon la plus utile que m’a donnée chromedp, et ce n’est pas un bug — c’est la différence entre « j’ai rendu la page » et « j’ai attendu précisément ce que je voulais », une distinction que le folklore autour des navigateurs headless a tendance à aplatir. La stratégie d’attente, et non le navigateur, décide si vous récupérez les données. Tous les chiffres ici proviennent d’un jeu de test local que je contrôle, avec une vérité de référence enregistrée avant toute exécution, et les résumés bruts se trouvent dans le dossier chromedp de notre dépôt de benchmark.

Ce qu’est réellement chromedp

La pile chromedp est volontairement courte. Pas de serveur Selenium. Pas de shim WebDriver. Pas de runtime Node caché en arrière-plan. Votre programme Go ouvre un WebSocket vers une instance Chrome et lui parle directement en CDP, à peu près le même protocole sur le fil que Puppeteer, mais sans le JavaScript.

Le dépôt affichait 13 212 étoiles et 178 issues ouvertes au moment de ma vérification le 27 juillet 2026, sous licence MIT. La version testée est v0.16.0, qui est le dernier tag du dépôt. Point important pour éviter toute confusion : la page GitHub Releases affiche encore v0.15.1 (publiée le 2026-04-01) comme dernier objet de release, tandis que go get github.com/chromedp/chromedp@latest résout vers v0.16.0. Les modules Go et les objets de release GitHub ont divergé ici. Ce n’est pas cassé, juste agaçant quand on essaie de comprendre ce qu’on exécute.

Le modèle mental repose entièrement sur les contextes Go. Vous créez un contexte d’allocator (qui sait lancer Chrome), puis un contexte navigateur à partir de celui-ci, et vous appelez ensuite chromedp.Run(ctx, actions...) avec une liste d’Actions. Un contexte enfant d’un contexte navigateur correspond à un nouvel onglet. Annulez un contexte, et l’objet qu’il représente disparaît. Si vous avez déjà fait un peu de concurrence en Go, cela vous sera immédiatement familier ; sinon, notre guide de démarrage du web scraping en Go est une entrée en matière bien plus douce que le godoc de chromedp.

Une limite à poser dès le départ : chromedp vous donne un DOM rendu. Il ne vous donne pas de données structurées. Tout ce que vous extrayez de ce DOM — champs, tableaux, prix — est du code que vous écrivez et entretenez. C’est un pilote, pas un framework de scraping.

La mécanique sous le capot

Dans chromedp, tout est un Action, et Run exécute une tranche de ces actions dans l’ordre sur une cible. Navigate, Click, Evaluate, OuterHTML, WaitVisible — tout repose sur la même interface, tout est composable, et tout n’est au fond qu’une commande CDP déguisée en type Go. Cette uniformité est la meilleure décision de conception de la bibliothèque, car elle place le sucre syntaxique et le protocole brut au même niveau.

Et c’est important, parce que le sucre est volontairement mince. chromedp s’appuie sur cdproto, un ensemble généré de bindings Go typés couvrant l’ensemble de la surface du DevTools Protocol, et le godoc chromedp documente les deux couches côte à côte. Quand l’action de confort n’existe pas, vous retombez sur l’appel de domaine — network.Enable(), page.CaptureScreenshot(), runtime.Evaluate() — au sein du même Run. Il n’y a pas de mur entre « la belle API » et « la vraie API », ce qui n’est pas le cas de tous les pilotes de navigateur.

Les actions d’attente sont l’endroit où se joue le jugement au quotidien, et il y en a plus que la plupart des gens n’en utilisent :

Action d’attenteCe qu’elle bloque
WaitReady(sel)jusqu’à ce que le nœud soit attaché au DOM
WaitVisible(sel)jusqu’à ce que le nœud soit réellement visible
WaitNotPresent(sel) / WaitNotVisible(sel)les inverses, utiles pour les spinners
Poll(js, res)évalue un prédicat JavaScript à intervalle régulier jusqu’à ce qu’il soit vrai

La gestion des processus est l’autre mécanique qu’il vaut la peine de connaître, car c’est elle qui détermine si votre programme laisse un navigateur en arrière-plan. chromedp lance Chrome via exec.CommandContext de Go. Annuler ce contexte tue le processus. Ce seul détail d’implémentation explique à la fois le bon comportement et l’effet de bord que j’ai constaté pendant les tests.

L’installation, c’est un binaire Go plus un Chrome que vous devez fournir

go get github.com/chromedp/chromedp s’est résolu proprement en v0.16.0 sans aucune difficulté, et l’arbre des dépendances ne contient aucune importation cgo. Donc l’affirmation « pure Go, sans dépendances externes » que l’on voit souvent est vraie — pour le module Go.

Elle ne l’est pas pour l’exécution. chromedp pilote un Chrome externe, et sans Chrome sur la machine, l’exécution échoue immédiatement. Chaque mesure que j’ai prise fournissait l’exécutable exact via chromedp.ExecPath, pointant vers un Chrome for Testing headless shell 151.0.7922.10. Ce n’est pas une critique — pour piloter un navigateur, il faut un navigateur — mais « aucune dépendance externe » et « vous devez livrer un Chrome de 155 Mo à côté de votre binaire » sont deux histoires de déploiement très différentes, et une seule apparaît dans le README.

Un second piège de configuration m’a coûté du temps et mérite d’être connu avant d’écrire la moindre ligne. Le ticket chromedp #1591 signale que le runner go test de Go 1.25+ annule NewExecAllocator en plein démarrage ; le même code fonctionne sans problème en binaire compilé. J’ai donc construit un binaire de test avec go build et je l’ai utilisé pour toutes les mesures au lieu de passer par go test. Ici, Go était en 1.26.5, sur macOS arm64. Si votre première expérience chromedp est un fichier de test qui meurt pendant le démarrage de Chrome, commencez par lire cette issue avant d’accuser votre propre code.

Pratique : quatre façons de lire la même page, dont deux sont vides

Measured results chart: Which read strategy saw each link?

Le jeu de test est un serveur local sur 127.0.0.1 qui sert trois types de contenu ne différant que par le moment où ils entrent dans le DOM : un <a> statique dans les octets servis, un <a> créé par un <script> inline pendant le parsing initial, et un <a> créé par setTimeout un nombre configurable de millisecondes après l’événement load. Les marqueurs et les hrefs des deux liens créés par script sont assemblés à partir de fragments de chaîne en JavaScript, de sorte qu’aucun littéral contigu n’existe dans les octets servis. Un résultat « trouvé » prouve donc que Chrome a exécuté JavaScript, pas qu’un simple lecteur d’HTML a fait son travail.

Le rappel est calculé en Python à partir de marqueurs de vérité de référence préenregistrés, pas dans le binaire Go de test, donc le test ne peut pas tricher en connaissant la réponse. Chaque stratégie a été exécutée trois fois ; les ensembles trouvés étaient identiques sur les trois exécutions.

Stratégie de lectureLien HTML statiqueInjecté au parsingInjecté 800 ms après le chargementTemps écoulé
Navigate + lecture, sans attentetrouvétrouvémanqué317 ms
WaitReady("body")trouvétrouvémanqué107 ms
WaitVisible("#delayed-injected")trouvétrouvétrouvé912 ms
Poll jusqu’à l’apparition du marqueurtrouvétrouvétrouvé972 ms

Deux lignes récupèrent deux liens sur trois. La lecture naïve manque le troisième lien parce que Navigate revient à l’événement load et que ce lien n’existe pas encore. WaitReady("body") rate pour une raison plus subtile, et pire en pratique : body est attaché au chargement, donc l’attente est satisfaite immédiatement et vous avez l’impression d’avoir fait la bonne chose. Elle est revenue en 107 ms, plus vite que le chemin sans attente, et vous a donné la même page incomplète.

Pour confirmer le mécanisme plutôt que le supposer, j’ai fait varier le délai d’injection et relancé les deux extrêmes (recall-summary.json) :

Délai d’injection après chargementLa lecture sans attente le voitWaitVisible le voitTemps de WaitVisible
0 msoui (course)oui109 ms
100 msnonoui208 ms
400 msnonoui519 ms
800 msnonoui911 ms
1500 msnonoui1625 ms

Le temps écoulé de WaitVisible suit le délai d’injection sur ce jeu de test — 100 à 208, 400 à 519, 800 à 911, 1500 à 1625 — preuve qu’il a bien bloqué jusqu’à l’apparition du nœud au lieu de lire trop tôt. La ligne à 0 ms marque la frontière : setTimeout(…, 0) peut s’exécuter avant la lecture immédiate, donc le chemin sans attente peut l’attraper. À partir de 100 ms dans ce balayage, le chemin sans attente l’a manqué à chaque exécution.

En production, la même erreur de timing peut produire un HTML valide avec zéro ligne extraite et un code de sortie 0, sauf si le pipeline vérifie la cardinalité de sortie. Il s’agit d’un mode de panne plausible, étayé par le comportement du jeu de test, et non d’un incident mesuré ici. Le rendu ne représente que la moitié de l’exigence ; la lecture doit attendre une condition métier liée aux données recherchées.

WaitReady et WaitVisible ne sont pas en concurrence — ils répondent à des questions différentes

La formulation habituelle dit que WaitVisible serait « plus fiable » que WaitReady. C’est assez imprécis pour devenir trompeur. Sur une page avec un nœud attaché au DOM mais stylé display: none, les deux divergent nettement (waitsem-summary.json, trois exécutions identiques) :

Nœud cibleActionRésultatTemps
attaché, display:noneWaitReadyrevient~6 ms
attaché, display:noneWaitVisibleexpire, context deadline exceeded4000 ms
nœud visibleWaitVisible, requête par défautrevient4–12 ms
nœud visibleWaitVisible, ByIDrevient1–2 ms
nœud visibleWaitVisible, ByQueryrevient1 ms

WaitReady signifie attaché. WaitVisible signifie visible. Posez la mauvaise question et vous passerez à côté d’un contenu qui n’a jamais été rendu, ou vous bloquerez pendant tout votre timeout sur un nœud qui n’avait de toute façon aucune chance d’être visible. Le comportement du délai est propre — un vrai context deadline exceeded exactement à 4 s, sans blocage ni état zombie — ce qui est déjà mieux que ce que proposent certains pilotes.

Un piège signalé n’a pas pu être reproduit. L’issue #440 décrit WaitVisible("#id") qui reste bloqué avec la requête par défaut, et cela ne s’est pas reproduit sur v0.16.0 — la requête par défaut, ByID et ByQuery ont tous répondu sur le nœud visible à chaque exécution. Non reproduit ne veut pas dire corrigé : il s’agit d’une forme de sélecteur sur une page, ce qui ne clôt pas l’issue.

Le defer cancel() que vous avez sauté soutient tout l’édifice

On compte les processus, pas les valeurs de retour. Chaque exécution de cycle de vie utilisait un --user-data-dir unique et comptait les vrais processus browser Chrome avec pgrep, en filtrant les processus renderer enfants. Chaque chemin a été exécuté trois fois (lifecycle-summary.json).

Chemin de sortie (macOS, 3 exécutions chacun)Sort du chrome-headless-shell lancéTemps
Annuler le contexte et l’allocatordisparu13, 13 et 12 millisecondes
Quitter le processus Go sans annulersurvit à votre programme — zéro processus navigateur avant, un après la sortie du test ; orphelin sur trois exécutions sur trois

L’annulation est propre, rapide, exactement ce que promet exec.CommandContext. (Chaque orphelin a ensuite été tué de force par le harness ; l’hôte a été nettoyé.)

C’est un comportement connu, documenté et circonscrit à une plateforme — la mesure est mienne, pas la découverte. Le tracker de chromedp l’a couvert sous plusieurs angles : #774 décrit le même non-quitté sous FreeBSD, #752 signale des processus Chromium bloqués sur macOS, et #562 ainsi que #1566 expliquent le mécanisme. Ce que j’ajoute, ce sont le nombre de processus et le timing des deux côtés de la comparaison, ce que ces rapports qualitatifs n’apportent pas.

Le mécanisme lui-même relève des build tags. Dans le source v0.16.0, allocate_linux.go définit Pdeathsig = SIGKILL sur le processus enfant, donc Linux obtient un signal de mort du parent au niveau du noyau. allocate_other.go, qui est ce que compile macOS, transforme cet appel en no-op. Il n’existe pas de signal équivalent sur darwin, donc rien ne tue Chrome lorsque votre programme s’arrête. Pendant ce temps, le texte du godoc donne l’impression d’une promesse générale — la commande par défaut « envoie SIGKILL à tous les navigateurs ouverts lorsque le programme Go se termine » — alors que la portée Linux n’existe que dans du code protégé par build tags que vous devez aller lire. Dire que la documentation surestime la portée est justifié ; dire que c’est un bug chromedp ne l’est pas.

La conséquence pratique reste la même : sur macOS, defer cancel() est indispensable. Omettez-le et chaque exécution laissera un processus navigateur derrière elle. Je n’ai pas testé Linux, donc je ne généralise pas ce résultat d’orphelin là-bas — le code source suggère que Linux se comporte différemment, et une suggestion n’est pas une mesure.

Démarrage à froid, concurrence et détails ennuyeux qui déterminent votre déploiement

Measured results chart: Cold start and two concurrency shapes

102 ms était la médiane entre processus fraîchement lancé, allocator, contexte, navigation localhost et premier Evaluate sur cinq processus, avec une plage de 98 à 111 ms (coldstart-summary.json). Sur ce jeu de test macOS arm64 avec un headless shell déjà chaud sur disque, le démarrage restait faible comparé à l’attente sur le contenu différé. Les conteneurs, systèmes de fichiers froids, CI, environnements serverless et navigations de production n’ont pas été mesurés.

Côté concurrence, chromedp propose deux schémas — un navigateur avec plusieurs contextes enfants (onglets), ou plusieurs navigateurs indépendants. Quatre navigations, trois exécutions chacune (concurrency-summary.json) :

ModeTemps global (p50)PlageNombre maximal de processus navigateur Chrome
Navigateur partagé, 4 contextes enfants214 ms209–2191
4 navigateurs séparés264 ms261–2784

Le résultat mesuré le plus parlant est le nombre de processus : un seul processus navigateur Chrome contre quatre pour ces quatre navigations locales triviales. Les plages de temps ne se chevauchent pas, mais elles restent indicatives plutôt qu’un benchmark de débit. RSS et PSS n’ont pas été mesurés, donc ce test ne démontre pas d’économie mémoire.

La petite vérification du chemin d’erreur n’est pas assez détaillée ici pour soutenir une affirmation de robustesse : le brouillon n’indique pas si le statut HTTP, l’erreur de navigation, l’événement ou la logique du harness a révélé chaque condition. Considérez donc la gestion des 500/liens morts comme non documentée jusqu’à publication du résultat exact de l’API et de l’artefact brut.

Non testé, et donc hors du périmètre de ces chiffres : le comportement de cycle de vie sous Linux, la concurrence au-delà de N=4 ou avec de vrais traitements par page, les variations mémoire (j’ai compté les processus, pas le RSS), l’interception réseau et la capture des requêtes, ainsi que les rapports ouverts sur les timeouts de WaitReady dans #168 et #1593 — ils décrivent des timeouts intermittents, alors que ce que j’ai mesuré concerne la sémantique des attentes, une question différente. Une machine, une build Chrome.

chromedp n’est pas le seul pilote Go CDP sur ce banc : rod a subi exactement le même jeu de test, le même harness, le même hôte et la même build Chrome au cours de la même session, et dispose de son propre compte rendu.

Avantages et inconvénients

Avantages :

  • Accès CDP réel — les actions de confort et les appels bruts cdproto se combinent dans le même Run, donc vous ne heurtez jamais une limite d’API.
  • Base locale de démarrage à froid à 102 ms p50, avec une plage de 98–111 ms sur le jeu de test macOS.
  • cancel récole Chrome en ~13 ms, de façon constante, à chaque exécution.
  • Les contextes enfants partagent un seul processus navigateur pour N onglets (1 processus contre 4 pour des navigateurs séparés).
  • Déterministe en test — les ensembles de rappel, la sémantique des attentes et les résultats de cycle de vie étaient identiques sur trois répétitions chacun.
  • Gestion propre des délais : WaitVisible sur une condition inatteignable a renvoyé un vrai context deadline exceeded exactement à 4 s au lieu de bloquer.
  • Module pure Go (sans cgo), sous licence MIT ; un exécutable Chrome externe reste requis à l’exécution.

Inconvénients :

  • Nécessite un Chrome externe à l’exécution ; la réputation de « sans dépendances » ne concerne que le module Go.
  • WaitReady("body") est un piège qui semble correct et manque silencieusement le contenu post-chargement — il est revenu en 107 ms avec une page incomplète.
  • Le chemin naïf Navigate + lecture manque tout ce qui est injecté à partir d’environ 100 ms après le chargement, de façon déterministe, sans erreur.
  • Sur macOS, sortir sans cancel() laisse le navigateur orphelin (3/3 exécutions). Comportement connu et limité à la plateforme, mais très facile à déclencher.
  • La formulation du godoc sur le SIGKILL à la sortie donne l’impression d’une portée universelle alors que le mécanisme n’existe que dans du code Linux conditionné par build tags.
  • go test sur Go 1.25+ peut annuler le démarrage de l’allocator (#1591) ; construisez un binaire à la place.
  • Il renvoie un DOM, pas des données structurées — chaque champ que vous voulez nécessite du code de parsing que vous possédez et entretenez.
  • Le dernier tag (v0.16.0) est en avance sur le dernier objet GitHub Release (v0.15.1), ce qui rend la vérification de version brièvement déroutante.

À qui chromedp s’adresse, et qui devrait l’éviter

Si votre service est déjà en Go et que vous avez besoin d’un vrai navigateur à l’intérieur, chromedp est presque le choix évident. Pas de processus Node à superviser, pas de serveur WebDriver à maintenir en vie, un seul binaire compilé plus un Chrome que vous fournissez ou installez. Le modèle de contexte se mappe sur les primitives de concurrence de Go de manière si directe que la durée de vie du navigateur finit par être gouvernée par la même discipline defer que le reste de votre codebase. Et si vous avez besoin de quelque chose que l’API de confort ne couvre pas — événements réseau CDP, hooks précis du cycle de vie des pages, astuces au niveau du protocole — vous basculez vers cdproto sans quitter la bibliothèque.

C’est aussi un bon choix quand vous voulez un contrôle explicite des attentes. Les actions d’attente sont des primitives, pas des heuristiques ; elles font exactement ce qu’elles annoncent, ce qui devient un avantage une fois que vous acceptez que choisir correctement est désormais votre responsabilité.

Évitez-le si votre équipe n’écrit pas en Go — l’engagement langage est le vrai coût, pas la bibliothèque. Évitez-le si vous voulez une ergonomie d’auto-attente qui devine correctement à votre place, car chromedp ne devine pas ; il fera exactement ce que vous avez demandé et vous renverra l’état de la page à cet instant précis. Évitez-le, ou budgétez-le sérieusement, si ce dont vous avez réellement besoin ce sont des enregistrements structurés plutôt qu’un DOM : chaque champ est un sélecteur que vous écrivez, testez et réparez lorsque le site change. Et si « donnez-moi juste les données de ces 500 URL » est l’unique exigence, mettre en place une orchestration de navigateur en Go représente beaucoup de mécanique pour la demande. Notre guide de l’automatisation navigateur explique quand cette mécanique vaut son coût et quand elle ne vaut pas le coup.

Alternatives, y compris la place de notre propre stack

Dans la catégorie des pilotes de navigateur, rod est un autre pilote Go CDP, tandis que Playwright et Puppeteer sont des options côté Node couvertes dans notre comparatif Playwright vs Puppeteer. Leurs contrats d’attente ne sont pas interchangeables. Playwright attend automatiquement la « actionability » avant de nombreuses actions ; cela ne lui dit pas pour autant quand les données applicatives ont fini d’arriver après l’action. chromedp vous donne des primitives d’attente de plus bas niveau et laisse à l’appelant à la fois l’actionability et la condition de disponibilité métier. Si vous explorez le paysage plus large, notre tour d’horizon des scrapers open source testés couvre les crawlers statiques et les bibliothèques d’extraction de l’autre côté de cette ligne.

Lecture connexe : Test de Browserless.

Un service d’extraction managé appartient à une autre catégorie. Il échange le contrôle du navigateur et des sélecteurs contre le rendu externalisé et la structuration du schéma. Cela peut être utile quand le livrable attendu est un jeu de données structuré plutôt qu’un DOM, alors que chromedp est plus adapté lorsque le navigateur doit rester sous le contrôle de votre service Go. Nous construisons Thunderbit, qui est un tel service, mais nous ne l’avons pas exécuté sur ce jeu de test ; cette étude ne permet donc aucune comparaison d’équivalence, de latence, de qualité d’extraction ni de coût avec chromedp.

Essayez Thunderbit pour l’extraction de données web

Verdict

Faut-il utiliser chromedp ? Oui, si vous codez en Go et que vous voulez un vrai navigateur sous votre contrôle. Dans ce jeu de test local, il a atteint le premier résultat de script en 102 ms p50, a réuni Chrome en environ 13 ms après annulation, et n’a utilisé qu’un seul processus navigateur pour quatre onglets concurrents. Ce sont des observations bornées, pas des promesses universelles de performance ; l’attrait durable, c’est l’accès CDP direct depuis Go quand la couche de confort ne suffit plus.

Il faut simplement calibrer correctement les affirmations, car la réputation survend deux choses. « Pure Go, sans dépendances » décrit le module ; à l’exécution, vous distribuez et gérez un binaire Chrome. Et « utilisez un navigateur headless et vous récupérerez le contenu dynamique » n’est vrai que lorsque votre attente est alignée sur le nœud voulu — une lecture naïve et WaitReady("body") m’ont toutes deux renvoyé une page dépourvue du contenu injecté 800 ms après le chargement, silencieusement, à chaque fois. Sur macOS, defer cancel() n’est pas une préférence de style ; si vous l’omettez, vous laissez fuiter un navigateur par exécution, ce qui relève d’un comportement connu de la plateforme mais reste votre problème à gérer. Si vous faites ces trois choses correctement, chromedp fait partie des pilotes de navigateur les plus prévisibles que j’aie mesurés. Si vous les ratez, il échouera en silence, ce qui est la pire façon d’échouer pour un scraper.

Essayez Thunderbit pour l’extraction de données web Get Started Free

FAQ

chromedp voit-il réellement le contenu rendu par JavaScript ? Oui — mais seulement avec une attente alignée sur le nœud voulu. Sur un jeu de test où un lien était injecté 800 ms après l’événement load, Navigate plus une lecture l’a manqué, et WaitReady("body") l’a manqué aussi, tandis que WaitVisible sur ce nœud et un poll JavaScript l’ont tous deux récupérés, dans trois exécutions sur trois pour chaque cas. En faisant varier le délai, la lecture sans attente a manqué le nœud dès 100 ms et au-delà. Le rendu est nécessaire ; attendre correctement est ce qui le rend suffisant.

Quelle est la différence entre WaitReady et WaitVisible ? WaitReady bloque jusqu’à ce que le nœud soit attaché au DOM. WaitVisible bloque jusqu’à ce qu’il soit réellement visible. Sur un nœud attaché mais stylé display: none, WaitReady a répondu en environ 6 ms tandis que WaitVisible a attendu jusqu’à la deadline du contexte de 4 secondes avant de renvoyer un propre context deadline exceeded. Aucun des deux n’est « plus fiable » — ils répondent à des questions différentes, et choisir le mauvais est le vrai piège.

Ai-je vraiment besoin de defer cancel() avec chromedp ? Sur macOS, oui. L’annulation du contexte et de l’allocator a récollecté le Chrome lancé en 12–13 ms à chaque exécution ; quitter le processus Go sans annuler a laissé un navigateur orphelin derrière lui dans les trois exécutions. C’est un comportement connu et limité à la plateforme — le tracker de chromedp documente le même schéma de non-quitté sur d’autres systèmes non Linux, et le kill par parent-death qui gère cela vit dans du code Linux protégé par build tags. Je n’ai pas testé Linux, donc considérez le résultat d’orphelin comme limité à macOS.

chromedp a-t-il besoin que Chrome soit installé séparément ? Oui. Le module Go lui-même est pure Go, sans cgo, mais il pilote un navigateur externe et échoue immédiatement sans lui. J’ai fourni explicitement un headless shell Chrome for Testing 151.0.7922.10 via chromedp.ExecPath. L’avantage, c’est que le coût de démarrage est faible : un cycle froid complet jusqu’au premier résultat de script affichait une médiane de 102 ms sur cinq processus frais, avec une plage de 98–111 ms.

Dois-je partager un seul navigateur entre plusieurs onglets ou lancer plusieurs navigateurs ? Préférez les contextes enfants quand l’objectif est de minimiser le nombre de processus navigateur. Quatre navigations localhost via un seul navigateur ont utilisé 1 processus navigateur Chrome ; quatre navigateurs séparés en ont utilisé 4. Le temps global favorisait aussi la configuration partagée (214 ms contre 264 ms en médiane), mais quatre pages locales triviales ne constituent pas un benchmark de débit. La mémoire n’a pas été mesurée. Des navigateurs séparés peuvent rester le bon choix si vous avez besoin d’une isolation de session plus forte, de proxies différents ou d’un rayon de blast d’arrêt plus petit ; ces arbitrages étaient hors du périmètre de ce test.

Ke
Ke
CTO chez Thunderbit | Data Scientist senior et expert en ML Forte d’une expérience de près de dix ans en machine learning et en data science, Ke Shen est diplômé de Columbia University et ancien Data Scientist senior chez Walmart Labs. Grâce à une expertise approfondie, reconnue par ses pairs, en Python, R, Java et statistiques, il partage des analyses éprouvées sur le passage d’algorithmes d’IA complexes de la théorie à une architecture prête pour la production.
Table des matières
Thunderbit · Agent IA de données web

Extrayez des données de n'importe quelle page en 1 clic

Approuvé par plus de 250 000 utilisateurs
formule gratuite disponible
De la page web au tableur
Décris ce dont tu as besoin — l'agent IA de Thunderbit l'extrait et l'exporte vers Excel, Google Sheets, Airtable ou Notion. Gratuit pour commencer.
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week