Extensions Chrome
Chargez des extensions non empaquetées au lancement avec extensions. Manifest V2 et V3 fonctionnent tous les deux, avec interface comme en headless, sous Windows et Linux.
En charger une
Passez une liste de répertoires d’extensions non empaquetées — chacun étant un dossier qui contient un manifest.json — à launch(), launch_persistent_context() ou serve() (.NET : Extensions = new[] { ... }). Elles se chargent dans le profil du navigateur ; les seuls lancements qui ne peuvent pas les prendre en charge sont donc ceux en mode incognito (ephemeral_profile=False, le launch() de l’API asynchrone, LaunchAsync en .NET). Les extensions concernent les navigateurs que vous démarrez avec le SDK ; les navigateurs hébergés ne les chargent pas.
from clearcote import launch_persistent_context
ctx = launch_persistent_context(
"./profile",
extensions=["./ext/ublock", "./ext/my-helper"], # unpacked directories
)
page = ctx.pages[0] if ctx.pages else ctx.new_page()
page.goto("https://example.com")import { launchPersistentContext } from "clearcote";
const ctx = await launchPersistentContext("./profile", {
extensions: ["./ext/ublock", "./ext/my-helper"],
});Le SDK définit pour vous à la fois --load-extension et --disable-extensions-except. Cette association compte : employé seul, --load-extension est ignoré sous automatisation, et c’est la raison habituelle pour laquelle une extension n’apparaît pas, sans le moindre message.
Obtenir un répertoire non empaqueté
Clearcote charge des dossiers, pas des fichiers .crx. Un .crx est un ZIP doté d’un en-tête de signature ; il suffit donc de le décompresser pour obtenir un répertoire chargeable :
unzip extension.crx -d ./ext/extensionClearcote ne peut ni installer ni mettre à jour des extensions depuis le Chrome Web Store — les patchs de confidentialité upstream suppriment cette intégration. Livrez le répertoire décompressé avec votre automatisation et mettez-le à jour vous-même : les extensions chargées de cette façon ne se mettent jamais à jour d’elles-mêmes. C’est le même modèle que celui de Playwright et Puppeteer.
Manifest V2 fonctionne toujours
Chrome standard n’exécute plus les extensions Manifest V2. Clearcote, si, car le jeu de patchs de confidentialité upstream rétablit cette prise en charge — les bloqueurs de contenu réservés à MV2 et les anciens outils maison continuent donc de fonctionner ici, alors qu’ils ne fonctionnent plus dans Chrome.
# both of these load and run
ctx = launch_persistent_context("./profile", extensions=["./ext/mv2-tool", "./ext/mv3-tool"])Headless
Les extensions se chargent en mode headless comme avec interface. Aucun flag supplémentaire, et nul besoin de faire tourner un serveur d’affichage juste pour faire fonctionner une extension.
ctx = launch_persistent_context("./profile", extensions=["./ext/my-helper"], headless=True)Ce qu’il faut savoir côté empreinte
Une extension, c’est votre code qui s’exécute dans votre profil, et Clearcote ne la masque pas. Il en découle deux choses, et chacune mérite d’être tranchée délibérément plutôt que découverte après coup.
- Les extensions sont observables. Un content script qui réécrit le DOM, injecte des styles ou bloque des requêtes modifie ce que mesure une page. Un site qui compare son propre balisage à ce qu’il a servi peut déceler que quelque chose a modifié la page. C’est vrai de tout navigateur doté d’extensions, et ce n’est pas un signal propre à Clearcote, mais c’en est bien un.
- Les ressources accessibles depuis le web peuvent être sondées. Si une extension déclare
web_accessible_resources, n’importe quelle page peut tenter de récupérerchrome-extension://<id>/<file>et apprendre ainsi que l’extension est présente. Préférez les extensions qui n’en déclarent aucune, et gardezuse_dynamic_urlà l’esprit pour celles qui doivent en déclarer.
Si votre objectif est de bloquer des requêtes plutôt que de fournir une interface, envisagez de le faire dans la couche d’automatisation avec Network.setBlockedURLs de CDP — il bloque par motif d’URL, n’ajoute aucune surface d’extension et conserve le cache du navigateur (page.route() de Playwright fonctionne aussi, mais désactive le cache). Consultez Réglages recommandés pour le principe général : ne falsifiez que ce dont vous avez besoin, et n’ajoutez de surface que si elle se justifie.
Dépannage
- Rien ne se passe. Vérifiez que le chemin pointe vers le dossier qui contient
manifest.json, et non vers son dossier parent ni vers un.crx. - Le content script ne s’exécute jamais. Vérifiez que le motif
matchescouvre l’URL que vous visitez —http://localhost/*ne correspond pas àhttp://127.0.0.1:8080/. - Ça marche avec interface, mais pas en headless. Cela ne devrait pas arriver sur ce build : les deux fonctionnent. Si cela vous arrive, ouvrez une issue en joignant le manifest.