Zwei Flags tauchen in Beispielen zur Erweiterungs-Automatisierung immer wieder auf:
--disable-extensions-except=/path/to/ext --load-extension=/path/to/ext
Ältere Anleitungen verweisen Puppeteer oder Playwright auf ein installiertes Chrome und übergeben beide Flags.
In dem hier getesteten Standard-Build von Google Chrome 150 startete der Browser zwar ohne Fehler in der Befehlszeile, aber der Erweiterungsdienst ignorierte beide Flags. Die Automatisierung stellte die Verbindung normal her, die Erweiterung fehlte jedoch; das verzögerte Symptom war in diesem Test-Setup ein Selector-Timeout.
Chrome protokollierte die Ablehnung in einer einzigen Zeile, aber erst nachdem das Logging auf stderr aktiviert worden war.
Die wichtigste Erkenntnis ist der Vergleich zwischen unterschiedlichen Browser-Builds. Die zwei späteren Abschnitte sind ausdrücklich Hinweise zum Test-Setup: Einer behandelt von Erweiterungen ausgelöste Downloads, der andere diesen Installationspfad per Befehlszeile auf file://-Fixtures. Thunderbit selbst ist eine Chrome-Erweiterung, daher haben wir ein direktes Interesse an diesem Problem; Thunderbit war jedoch nicht das Testziel.
Die entscheidende Zeile
Füge --enable-logging=stderr hinzu und starte das Standard-Chrome mit diesen Flags:
Offizielle Referenz: Quellcode des Chromium-Erweiterungsdienstes.
WARNING:chrome/browser/extensions/extension_service.cc:442]
--disable-extensions-except is not allowed in Google Chrome, ignoring.
Wenn du --load-extension allein übergibst, erscheint eine eigene Warnung aus einer anderen Zeile derselben Datei:
WARNING:chrome/browser/extensions/extension_service.cc:420]
--load-extension is not allowed in Google Chrome, ignoring.
Chrome for Testing gibt bei identischen Flags keine dieser Meldungen aus.
„Not allowed in Google Chrome.“ Diese Warnung legt nahe, dass es sich um eine Regel des gebrandeten Builds handelt. Sie beweist, dass dieser Standard-Build von Google Chrome 150 das Flag ignoriert hat, und zeigt außerdem die relevante Stelle im Code. Sie beweist jedoch nicht unabhängig, dass die Version selbst irrelevant ist, und sie legt den konkreten Implementierungsmechanismus nicht offen.
Alles Weitere unten dient der Bestätigung und den Konsequenzen.
Verhaltenstechnisch bestätigt
Eine minimale MV3-Erweiterung, eigens für diesen Test gebaut statt heruntergeladen, verwendet ein Content Script, ein Popup, einen Roundtrip per Nachricht, DOM-Auslesung und einen chrome.downloads-Export gegen ein lokales Fixture mit drei Produkten. Das Test-Setup dokumentiert sechs nummerierte Prüfungen: Service Worker registriert; Erweiterungsmarker trägt eine ID; Content-Script-Marker stimmt; Popup-Button sichtbar; Popup gibt drei Zeilen zurück; erfasste CSV enthält die erwartete Zeile. Eine separate Übereinstimmungsprüfung vergleicht die unabhängigen Signale von Service Worker und Seitenmarker.
Drei Builds verwendeten dieselben expliziten Erweiterungs-Flags, dasselbe Erweiterungsverzeichnis, dasselbe HTTP-Fixture, den geparkten persistenten Kontext im Headed-Modus und pro Durchlauf ein frisches Profil. Der Stock-Zweig wurde über channel: 'chrome' aufgelöst; die zwei erfolgreichen Zweige nutzten explizite Executable Paths. Die Versionsstrings wurden über CDP ausgelesen.
| Build | Vom Browser gemeldete Version | Service Worker der Erweiterung | Content Script injiziert | Voller 6-Punkte-Run |
|---|---|---|---|---|
| Chrome for Testing | Chrome/149.0.7827.55 | ✅ | ✅ | BESTANDEN 6/6 |
| Stock Google Chrome | Chrome/150.0.7871.187 | ❌ nie registriert | ❌ | FEHLER bei Schritt 0 |
| Chrome for Testing | Chrome/151.0.7922.10 | ✅ | ✅ | BESTANDEN 6/6 |
Rohzusammenfassungen: Chrome for Testing 149, Stock Chrome 150, Chrome for Testing 151 und stderr-Warnungen.
Chrome for Testing 149 ist absichtlich enthalten: Es ist älter als der Stock-Build, mit dem es verglichen wird. Wäre die Fähigkeit durch einen Versionssprung entfernt worden, müsste ein älterer Build auf der funktionierenden Seite liegen und der fehlerhafte Build der neueste sein. Stattdessen liegt der fehlerhafte Build zwischen zwei funktionierenden Builds – das spricht gegen eine einfache fortlaufende Versionsentwicklung.
Allein diese Tabelle beweist noch nicht, dass die Sperre build-basiert ist, und es ist wichtig, genau zu sagen warum. Die eine fehlerhafte Zelle ist gleichzeitig die einzige Stock-Zelle und die einzige 150-Zelle — Build und Version sind in diesem Design also weiterhin perfekt miteinander verknüpft. Drei Zweige schließen eine monotone Entfernung aus; sie schließen aber nicht aus, dass die Funktion in 150 regressiert und in 151 wiederhergestellt wurde. Das allein über das Verhalten zu belegen, würde eine Zelle erfordern, die diese Maschine nicht liefern kann: Chrome for Testing 150 oder einen gebrandeten Build mit einer anderen Version.
Die Warnung stützt die Interpretation eines gebrandeten Builds zusätzlich, weil sie explizit Google Chrome nennt, während das Drei-Zweig-Verhalten nur eine einfache monotone Entfernung ausschließt. Um einen versionsunabhängigen Mechanismus zu beweisen, bräuchte es dennoch einen Cross-Build-Vergleich mit derselben Version oder einen Quell-/Konfigurationsnachweis.
Die verlinkten Artefakte pro Build zeigen den zusammengefassten Lauf je Zweig; dieser Artikel veröffentlicht keine Run-für-Run-Matrix für die zusätzliche Launch-Anzahl und nutzt diese Zahl daher nicht als unabhängigen Beleg.
Ein Signal reicht nicht, um zu sagen „es wurde nicht geladen“
Die erste Version dieses Tests entschied, ob die Erweiterung geladen worden war, indem sie nach einem Marker suchte, den das Content Script in die Seite schreibt — und genau so entschied sie auch, ob das Content Script ausgeführt worden war. Ein einziger Wert, als zwei Messungen verwendet. Fehlt der Marker, lässt sich nicht unterscheiden zwischen „die Erweiterung wurde nie geladen“ und „sie wurde geladen, aber das Content Script wurde nicht injiziert“ — und diese beiden Fälle brauchen völlig unterschiedliche Korrekturen.
MV3-Erweiterungen laufen mit einem Hintergrund-Service-Worker, und Playwright stellt Service Worker direkt bereit. Das ist ein unabhängiges Signal: Es berührt die Seite nicht und kann daher nicht mit der Injektion verwechselt werden. Der aktuelle Test liest beide Signale aus und prüft, ob sie übereinstimmen.
In allen drei Läufen stimmen sie überein. Auf Stock Chrome wurde nie ein Service Worker registriert — die starke Form der Aussage. Auf beiden Chrome-for-Testing-Builds war der Worker bereits unter chrome-extension://<id>/background.js aktiv, bevor die Seite überhaupt geöffnet wurde.
Verwende Chrome for Testing, das du möglicherweise schon hast
Die beiden erfolgreichen Zweige nutzten explizite Chrome-for-Testing-Executables mit den Versionen 149.0.7827.55 und 151.0.7922.10. Richte Playwrights executablePath auf das fest gepinnte Executable statt Stock Chrome über channel: 'chrome' aufzulösen. npx playwright install chromium installiert einen von Playwright verwalteten Chromium-Build; auch das kann für Automatisierung nützlich sein, ist aber nicht dasselbe Distributionslabel wie die beiden Chrome-for-Testing-Zweige und war in diesem Vergleich kein vierter Zweig.
Offizielle Referenz: Ankündigung von Chrome for Testing.
Verwandte Analyse: Prüfung der Chrome-Erweiterungsberechtigungen.
Es gibt noch einen Nebeneffekt, der über diesen konkreten Fehler hinaus wichtig ist. Stock Chrome aktualisiert sich automatisch im Hintergrund, sodass ein Test, der heute besteht, am Dienstag aus Gründen fehlschlagen kann, die kein Commit erklärt. Chrome for Testing ist fest gepinnt. Für alles, dessen Ergebnis auch in drei Monaten noch etwas bedeuten soll, ist das wichtiger als Bequemlichkeit.
Hinweis zum Test-Setup: Den Erweiterungs-Export erfassen
Für eine Scraping-Erweiterung ist der Export der eigentliche Zweck — dort gehen Felder verloren, Encodings werden verfälscht und verschachtelte Daten werden falsch abgeflacht. Zwei Dinge daran sind undokumentiert, und beide sind problematisch.
| Was der Export-Lauf aufgezeichnet hat | Wert |
|---|---|
playwright_download_event_fired | false |
suggestedFilename | null |
| Dateiname, den die Erweiterung anfordert | probe-export.csv |
| Dateiname, der im Verzeichnis landet | download.csv |
| Dateiinhalte | Kopfzeile und alle drei Zeilen bleiben vollständig erhalten |
In diesem MV3-/Playwright-1.56.0-Setup hat chrome.downloads das Download-Event von Playwright nicht ausgelöst. Als die Erweiterung über die API eine CSV exportierte, löste waitForEvent('download') nicht aus. Das Test-Setup erfasste die Datei, indem es eine CDP-Sitzung öffnete, das Download-Verhalten explizit setzte und das Ausgabeverzeichnis las:
const cdp = await ctx.newCDPSession(page);
await cdp.send('Browser.setDownloadBehavior', {
behavior: 'allow', downloadPath: DIR, eventsEnabled: true,
});
Im selben Setup blieb der angeforderte Dateiname bei diesem CDP-Erfassungspfad nicht erhalten. Kopfzeile und alle drei Zeilen blieben intakt, aber probe-export.csv landete als download.csv. Das ist ein beobachtetes Verhalten für die getesteten Browser-Builds und die getestete Konfiguration, keine dokumentierte Invariante für jeden beliebigen Erweiterungs-Download. Prüfe den Inhalt getrennt vom Dateinamen.
Hinweis zum Test-Setup: file://-Verhalten für diesen Installationspfad
Beim Verifizieren dieses Punktes stellte sich eine weit verbreitete Behauptung als falsch heraus — und sie hatte es sogar in einen früheren Entwurf dieses Artikels geschafft: Content Scripts laufen nicht auf file://-Seiten, weil Erweiterungen standardmäßig keinen Dateizugriff haben.
Gemessen auf beiden Chrome-for-Testing-Builds, die Erweiterung per Befehlszeile geladen und direkt zu file:///…/fixture/index.html navigiert: Das Content Script wird ganz normal injiziert. Marker vorhanden, Erweiterungs-ID korrekt, beide Builds. Per Befehlszeile geladene entpackte Erweiterungen erhalten Dateizugriff; der oft erinnerte Schalter „Dateizugriff gewähren“ gehört zu einem anderen Installationspfad.
Fixtures über HTTP bereitzustellen ist weiterhin die bessere Standardeinstellung, weil ein file://-Seite realen Zielen nicht entspricht. Das ist aber ein Argument für Realitätsnähe, keine technische Notwendigkeit — und der dafür üblicherweise genannte Mechanismus ist falsch.
Was das nicht beweist
- Die Implementierung der Sperre ist nur so tief belegt wie die Warnmeldung selbst. Chrome sagt, dass diese Flags in diesem Build nicht erlaubt sind, und nennt die Quelldatei. Ob das von Build-Konfiguration, Policy-Verkabelung oder etwas anderem gesteuert wird, wurde aus dem Quellcode nicht ausgelesen.
- Das ist nur eine Maschine. macOS auf arm64, eine Stock-Patch-Version, zwei Chrome-for-Testing-Builds. Chrome bewegt sich schnell genug, dass das regelmäßig neu geprüft werden muss, statt es einfach zu zitieren.
- Das ist nur der
--load-extension-Pfad. Gepackte.crx-Installationen, Laden im Entwicklermodus und Enterprise-Allowlist-Policies wurden nicht getestet. Nichts hier stützt die Aussage „Stock Chrome kann keine Erweiterungen ausführen“. - Die Erweiterung ist ein gezielt gebauter Stub. Er prüft die Mechanik, die jede Scraper-Erweiterung nutzt, aber eine echte Erweiterung ist größer und kann auf Arten fehlschlagen, die ein Stub nicht abbildet.
Was ich unterwegs falsch gemacht habe
Das ist ausdrücklich erwähnenswert, weil beide Fehler genau die Art sind, die eine Prüfung überstehen, wenn das Ergebnis plausibel aussieht.
Die erste Version dieses Textes behauptete, der Fehler sei still gewesen, es gebe keine Logzeile, und der Mechanismus sei nicht erkennbar — wer behaupte, ihn zu kennen, rate nur. Der Mechanismus lag eine Flag-Zeile entfernt, und Chrome hatte ihn die ganze Zeit auf WARNING-Level ausgegeben. Aus „Ich habe ihn nicht gefunden“ wurde fälschlich „Man kann ihn nicht finden“.
Der zweite Fehler war die oben erwähnte file://-Behauptung: aus Notizen übernommen und mit einer überzeugend klingenden Ursache versehen, bevor sie getestet worden war. Ein einzelner Lauf widerlegte sie.
Das Muster ist in beiden Fällen dasselbe. Eine plausible Aussage, an der niemand Anstoß nehmen würde, wird weitergetragen, weil Nachprüfen unnötig erscheint. Die Lösung ist nicht mehr Vorsicht in der Formulierung, sondern eine Regel dafür, was überhaupt gesagt werden darf: Eine Behauptung, die sich nicht auf einen Lauf zurückführen lässt, wird nicht veröffentlicht.
Befehle, die im lokalen Test-Setup verwendet wurden
Das versionierte Probe-Skript, der Erweiterungs-Stub, das Fixture und die Rohzusammenfassungen sind hier verlinkt, aber das ist noch kein eigenständiges öffentliches Reproduktionspaket. Die exakten Download-Quellen und Prüfsummen von Chrome for Testing 149 und 151 sind im Artikel nicht dokumentiert, und die unten verwendeten Executable Paths waren lokale Eingaben. Veröffentliche diese Browser-Quellen plus einen stabilen Repository-Commit, bevor du den vollständigen Vergleich als unabhängig reproduzierbar präsentierst.
Verwandte Analyse: Playwright-Review.
cd harness
npm install playwright@1.56.0
npx playwright install chromium # Playwright-Chromium; nicht die beiden CfT-Zweige unten
(cd fixture && python3 -m http.server 8731 &)
SP=$(pwd) OUT=cft-149.json LABEL=cft-149 EXE="<Chrome for Testing 149>" node probe_v2.mjs
SP=$(pwd) OUT=stock-150.json LABEL=stock-150 CHANNEL=chrome node probe_v2.mjs
SP=$(pwd) OUT=cft-151.json LABEL=cft-151 EXE="<Chrome for Testing 151>" node probe_v2.mjs
Dasselbe Skript und dieselben expliziten Erweiterungsargumente wurden für alle drei Zweige verwendet, aber die Auflösung des Executables war unterschiedlich: CHANNEL=chrome für Stock Chrome und EXE für die beiden Chrome-for-Testing-Binärdateien. Die Version in jeder Ausgabedatei wird aus dem Browser gelesen und nicht vom Label übernommen.
Für die Warnzeile braucht es kein Test-Setup:
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
--user-data-dir=/tmp/p --enable-logging=stderr \
--load-extension=/path/to/ext about:blank 2>&1 | grep "not allowed"
Stand: 2026-07-28.
Thunderbit für die Extraktion von Webdaten testen
Fazit und Vorbehalte
In der getesteten Matrix verweigerte Stock Google Chrome 150 die Kombination aus --disable-extensions-except und --load-extension, während Chrome for Testing 149 und 151 die Erweiterung luden. Chrome protokollierte die Ablehnung auf WARNING-Ebene: „--load-extension is not allowed in Google Chrome, ignoring.“ Die Formulierung spricht für einen gebrandeten Build, und die Versions-Sandwich-Struktur schließt eine einfache monotone Entfernung aus; Build und Version bleiben jedoch ohne einen Cross-Build-Zweig mit derselben Version oder ohne Quellen-/Konfigurationsnachweis miteinander verknüpft.
Für ein gepinntes Erweiterungs-Test-Setup solltest du ein explizit versioniertes Browser-Executable verwenden und sowohl den Service Worker als auch den Content-Script-Marker prüfen. In diesem Playwright-1.56.0-Setup erforderte der Erweiterungs-Export eine CDP-Erfassung des Verzeichnisses und landete unter einem anderen Dateinamen. Der per Befehlszeile geladene Stub injizierte außerdem auf dem getesteten file://-Fixture; andere Installationspfade wurden nicht getestet.
Thunderbit für die Extraktion von Webdaten testen Get Started Free
FAQs
Ist --load-extension aus Chrome komplett entfernt worden?
Nein. Chrome for Testing 149.0.7827.55 und 151.0.7922.10 luden den entpackten MV3-Stub beide über dieses Flag und bestanden alle sechs Prüfungen. Stock Google Chrome 150.0.7871.187 verweigerte es und protokollierte „--load-extension is not allowed in Google Chrome, ignoring“. Das stützt die Annahme einer Sperre in einem gebrandeten Build, beweist sie aber nicht: Das Verhalten schließt eine einfache monotone Entfernung aus, während ein nur in Chrome 150 auftretender und in 151 behobener Regression weiterhin mit dem Drei-Zweig-Design vereinbar wäre.
Warum sehe ich keinen Fehler, und wie unterscheide ich „nie geladen“ von „geladen, aber still fehlgeschlagen“?
Die Warnung wird nicht mit Standard-Verbosity ausgegeben. Starte mit --enable-logging=stderr, dann erscheint sie sofort; ohne diesen Schalter startet Chrome normal, aber sein Erweiterungsdienst ignoriert die Flags, und das erste sichtbare Problem im Test ist ein Selector-Timeout. Um „nie geladen“ von einem Injektionsfehler zu trennen, nutze zwei unabhängige Signale: den MV3-Hintergrund-Service-Worker und einen Content-Script-Marker im Ziel-DOM. Auf dem getesteten Stock-Chrome-Zweig erschien keiner von beiden; auf beiden Chrome-for-Testing-Zweigen erschienen beide.
Was sollte ich stattdessen zur Automatisierung von Erweiterungen verwenden?
Die erfolgreichen Zweige verwendeten fest gepinnte Chrome-for-Testing-Executables über executablePath. Ein von Playwright verwaltetes Chromium ist eine weitere mögliche Automatisierungs-Binärdatei, war hier aber kein Testzweig und sollte nicht ohne Prüfung des aufgelösten Executables als dieselbe Distribution beschrieben werden.
Warum löst waitForEvent('download') nie aus, wenn die Erweiterung eine Datei exportiert?
In diesem MV3-/Playwright-1.56.0-Setup wurde das Event nicht ausgelöst und es wurde kein vorgeschlagener Dateiname geliefert. Das Test-Setup öffnete eine CDP-Sitzung, rief Browser.setDownloadBehavior mit einem expliziten Verzeichnis auf und las dann die Datei von der Platte. In den getesteten Läufen blieben die CSV-Bytes erhalten, aber probe-export.csv kam als download.csv an; breitere Kombinationen aus Erweiterungen und Browsern wurden nicht getestet.
Was sagt das nicht aus — über file://-URLs und über Stock Chrome allgemein?
Zwei Grenzen, in entgegengesetzte Richtungen. Content Scripts funktionieren auf file://-URLs für Erweiterungen, die per Befehlszeile geladen wurden — getestet auf beiden Chrome-for-Testing-Builds, wobei das Script normal injiziert wurde und die Erweiterungs-ID korrekt erschien. Die verbreitete Behauptung, das gehe nicht, weil Erweiterungen standardmäßig keinen Dateizugriff hätten, ist für diesen Installationspfad also falsch. Fixtures über HTTP bereitzustellen ist trotzdem Best Practice, weil es einem realen Ziel ähnelt, nicht weil file:// die Injektion blockiert. In die andere Richtung gilt: Nichts davon sagt, dass Stock Chrome keine Erweiterungen ausführen kann. Gemessen wurde nur der Kommandozeilenpfad --load-extension. Gepackte .crx-Installation, Laden im Entwicklermodus und Enterprise-Allowlist-Policies wurden nicht getestet, und darüber wird keine Aussage getroffen. Der Fokus liegt auf genau dem Flag-Paar, das in Automatisierungsanleitungen empfohlen wird.


