Due flag ricorrono spesso negli esempi di automazione delle estensioni:
--disable-extensions-except=/path/to/ext --load-extension=/path/to/ext
Le guide più vecchie puntano spesso Puppeteer o Playwright verso un Chrome già installato e passano entrambi i flag.
Nella build standard di Google Chrome 150 testata qui, il browser si avviava senza errori da riga di comando, ma il servizio delle estensioni ignorava entrambi i flag. L’automazione si collegava come al solito e l’estensione non risultava caricata; il sintomo che arrivava più tardi era un timeout di selezione in questo harness.
Chrome registrava il rifiuto in una sola riga, ma solo dopo aver abilitato il logging su stderr.
Il risultato principale è il confronto tra build del browser. Le due sezioni successive sono note esplicite dell’harness: una riguarda i download attivati dall’estensione e l’altra questo percorso di installazione da riga di comando su fixture file://. Thunderbit è a sua volta un’estensione Chrome, quindi per noi questo problema è direttamente rilevante; Thunderbit non era il bersaglio del test.
La riga di log
Aggiungi --enable-logging=stderr e avvia Chrome standard con quei flag:
Riferimento ufficiale: sorgente del servizio estensioni di Chromium.
WARNING:chrome/browser/extensions/extension_service.cc:442]
--disable-extensions-except is not allowed in Google Chrome, ignoring.
Se passi solo --load-extension, ottieni il suo avviso dedicato, da un’altra riga dello stesso file:
WARNING:chrome/browser/extensions/extension_service.cc:420]
--load-extension is not allowed in Google Chrome, ignoring.
Chrome for Testing, con gli stessi flag, non stampa nessuno dei due.
“Non consentito in Google Chrome.” Questo avviso fa pensare prima di tutto a una regola specifica della build brandizzata, alla luce del comportamento osservato. Dimostra che questa build standard di Google Chrome 150 ha ignorato il flag e indica il punto del sorgente da cui proviene il messaggio. Però non dimostra da solo che la versione sia irrilevante, né svela il criterio di implementazione.
Tutto il resto qui sotto è conferma e conseguenza.
Conferma dal comportamento
Un’estensione MV3 minimale, costruita per questo test e non scaricata, usa content script, popup, round trip di messaggi, estrazione DOM ed esportazione con chrome.downloads su una fixture locale con tre prodotti. L’harness registra sei controlli numerati: service worker registrato; marker dell’estensione con ID; marker del content script corrispondente; pulsante del popup visibile; il popup restituisce tre righe; il CSV catturato contiene la riga attesa. Un’asserzione separata di coerenza confronta i segnali indipendenti del service worker e del marker nella pagina.
Tre build hanno usato gli stessi flag espliciti per l’estensione, la stessa directory dell’estensione, la stessa fixture HTTP, la stessa modalità persistent context con interfaccia visibile e un profilo nuovo per ogni ramo. Il ramo stock passava da channel: 'chrome'; i due rami che funzionano usavano executablePath espliciti. Le stringhe di versione sono state lette via CDP.
| Build | Versione riportata dal browser | Service worker dell'estensione | Content script iniettato | Esecuzione completa dei sei controlli |
|---|---|---|---|---|
| Chrome for Testing | Chrome/149.0.7827.55 | ✅ | ✅ | PASS 6/6 |
| Google Chrome standard | Chrome/150.0.7871.187 | ❌ mai registrato | ❌ | FAIL al passo 0 |
| Chrome for Testing | Chrome/151.0.7922.10 | ✅ | ✅ | PASS 6/6 |
Riepiloghi grezzi: Chrome for Testing 149, Chrome standard 150, Chrome for Testing 151 e warning su stderr.
Chrome for Testing 149 è incluso apposta: è più vecchio della build standard con cui viene confrontato. Se la capacità fosse stata rimossa con un salto di versione, una build più vecchia dovrebbe trovarsi sul lato funzionante della linea e quella fallita dovrebbe essere la più recente. Invece la build che fallisce si trova tra due build funzionanti, il che esclude una semplice progressione per versione.
Questa tabella, da sola, non dimostra che il blocco dipenda dalla build, ed è importante essere precisi sul perché. La sola cella che fallisce è contemporaneamente l’unica cella stock e l’unica cella 150: in questo disegno build e versione restano perfettamente confusi. Tre rami escludono la rimozione monotona; non possono escludere “regredito in 150, ripristinato in 151”. Per ricavarlo solo dal comportamento servirebbe una cella che questa macchina non può produrre: Chrome for Testing 150, oppure una build brandizzata con un’altra versione.
L’avviso rafforza l’interpretazione legata alla build brandizzata perché nomina esplicitamente Google Chrome, mentre il comportamento dei tre rami esclude solo una semplice rimozione monotona. Per dimostrare un meccanismo indipendente dalla versione servirebbe comunque un confronto tra build alla stessa versione o una citazione da sorgente/configurazione.
Gli artifact per singola build collegati sopra mostrano l’esecuzione riepilogata per ciascun ramo; questo articolo non pubblica una matrice run-by-run per il numero aggiuntivo di avvii, quindi non usa quel conteggio come prova indipendente.
Un solo segnale non basta per dire "non ha caricato"
La prima versione di questo test decideva se l’estensione fosse stata caricata guardando un marker scritto nel DOM dal content script — ed è anche così che decideva se il content script fosse partito. Un’unica lettura usata come due misure. Se il marker manca, non puoi distinguere tra “l’estensione non si è mai caricata” e “si è caricata ma il content script non si è iniettato”, e le due cose richiedono correzioni completamente diverse.
Le estensioni MV3 eseguono un service worker in background, e Playwright espone direttamente i service worker. È un segnale indipendente: non tocca mai la pagina, quindi non può essere confuso con l’iniezione. Il test attuale legge entrambi e verifica che coincidano.
In tutti e tre i run coincidono. Su Chrome standard non è mai stato registrato alcun service worker — la forma più forte dell’affermazione. Su entrambi i build Chrome for Testing il worker compare su chrome-extension://<id>/background.js prima ancora che la pagina venga aperta.
Usa Chrome for Testing, che forse hai già
I due rami funzionanti hanno usato eseguibili espliciti di Chrome for Testing che riportavano le versioni 149.0.7827.55 e 151.0.7922.10. Punta executablePath di Playwright sull’eseguibile bloccato invece di risolvere Chrome standard tramite channel: 'chrome'. npx playwright install chromium installa una build Chromium gestita da Playwright; può essere utile per l’automazione, ma non è la stessa distribuzione dei due rami Chrome for Testing e non costituiva un quarto ramo in questo confronto.
Riferimento ufficiale: annuncio di Chrome for Testing.
Revisione correlata: audit dei permessi dell’estensione Chrome.
C’è anche un vantaggio collaterale che dura oltre questo problema specifico. Chrome standard si aggiorna automaticamente sotto di te, quindi una suite che oggi passa può fallire martedì per motivi che nessun commit spiega. Chrome for Testing è bloccato a una versione. Per qualsiasi cosa il cui risultato debba avere ancora senso tra tre mesi, questo conta più della comodità.
Nota dell’harness: catturare l’export dell’estensione
Per un’estensione di scraping l’export è il punto centrale: è lì che si perdono campi, si rovinano le codifiche e si appiattiscono male i dati annidati. Due aspetti non sono documentati, e tutti e due si fanno sentire.
| Cosa ha registrato l'esecuzione di export | Valore |
|---|---|
playwright_download_event_fired | false |
suggestedFilename | null |
| Nome file richiesto dall'estensione | probe-export.csv |
| Nome file arrivato nella directory | download.csv |
| Contenuto del file | intestazione e tutte e tre le righe restano intatte |
In questo harness MV3/Playwright 1.56.0, chrome.downloads non ha attivato l’evento download di Playwright. Con l’estensione che esporta un CSV tramite l’API, waitForEvent('download') non si è risolto. L’harness ha catturato il file aprendo una sessione CDP, impostando esplicitamente il comportamento di download e leggendo la directory di output:
const cdp = await ctx.newCDPSession(page);
await cdp.send('Browser.setDownloadBehavior', {
behavior: 'allow', downloadPath: DIR, eventsEnabled: true,
});
Nello stesso harness, quel percorso di cattura via CDP non ha preservato il nome file richiesto. Intestazione e tutte e tre le righe sono rimaste intatte, ma probe-export.csv è arrivato come download.csv. Questo è un comportamento osservato per le build e la configurazione testate, non una regola invariabile per ogni download di estensione. Controlla il contenuto separatamente dal nome file.
Nota dell’harness: comportamento file:// per questo percorso di installazione
Durante la verifica di questo punto, una tesi molto ripetuta si è rivelata falsa, ed era finita in una bozza precedente di questo stesso articolo: che i content script non girino sulle pagine file:// perché le estensioni non hanno accesso ai file per impostazione predefinita.
Misurato su entrambe le build Chrome for Testing, caricando l’estensione da riga di comando e navigando direttamente a file:///…/fixture/index.html: il content script si inietta normalmente. Marker presente, ID dell’estensione corretto, entrambi i build. Le estensioni unpacked caricate da riga di comando ottengono accesso ai file; il toggle “consenti accesso ai file” che molti ricordano si applica a un percorso di installazione diverso.
Servire le fixture via HTTP resta comunque la scelta migliore, perché una pagina file:// non assomiglia affatto a un target reale. Ma è un argomento di realismo, non un requisito tecnico, e il meccanismo di solito invocato per giustificarlo è sbagliato.
Cosa non dimostra
- L’implementazione del blocco è visibile solo quanto lo è la stringa di warning. Chrome dice che questi flag non sono consentiti in questa build e indica il file sorgente. Se ciò dipenda da configurazione di build, da policy o da altro non è stato ricavato dal sorgente.
- Questa è una sola macchina. macOS su arm64, una patch version stock, due build Chrome for Testing. Chrome si muove abbastanza in fretta da richiedere una nuova verifica invece di una citazione statica.
- Questo riguarda solo il percorso
--load-extension. Installazioni.crximpacchettate, caricamento in modalità sviluppatore e policy enterprise con allowlist non sono state testate. Nulla qui supporta l’idea che “Chrome standard non possa eseguire estensioni”. - L’estensione è uno stub costruito apposta. Mette alla prova la meccanica che usa ogni estensione di scraping, ma una vera estensione è più grande e può fallire in modi che uno stub non può riprodurre.
Cosa avevo sbagliato arrivando fin qui
Vale la pena dirlo chiaramente, perché entrambi gli errori sono del tipo che sopravvivono alla revisione quando il risultato sembra corretto.
La prima versione di questo testo diceva che il fallimento era silenzioso, che non esisteva alcuna riga di log e che il meccanismo era impossibile da conoscere — che chiunque dicesse il contrario stesse tirando a indovinare. Il meccanismo era a un solo flag di distanza, e Chrome lo stampava già da sempre con severità WARNING. “Non sono riuscito a trovarlo” era stato riscritto come “non può essere trovato”.
Il secondo era l’affermazione su file:// sopra: ripresa da appunti e scritta con un meccanismo sicuro prima di essere testata. Un run l’ha falsificata.
Lo schema è lo stesso in entrambi i casi. Un’affermazione plausibile che nessuno avrebbe contestato, portata avanti perché controllarla sembrava superfluo. La soluzione non è più prudenza nella prosa, ma una regola su ciò che si può affermare: una tesi che non è tracciabile a un run non si pubblica.
Comandi usati nell’harness locale
Il probe versionato, lo stub dell’estensione, la fixture e i riepiloghi grezzi sono collegati qui, ma non si tratta ancora di un bundle pubblico di riproduzione autonomo. Le fonti di download e i checksum esatti di Chrome for Testing 149 e 151 non sono registrati nell’articolo, e i percorsi degli eseguibili qui sotto erano input locali. Pubblica quelle fonti del browser insieme a un commit stabile del repository prima di presentare l’intero confronto come indipendentemente riproducibile.
Revisione correlata: Playwright review.
cd harness
npm install playwright@1.56.0
npx playwright install chromium # Chromium gestito da Playwright; non i due rami CfT qui sotto
(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
Lo stesso script e gli stessi argomenti espliciti dell’estensione sono stati usati per tutti e tre i rami, ma la risoluzione dell’eseguibile differiva: CHANNEL=chrome per Chrome standard e EXE per i due binari Chrome for Testing. La versione in ciascun file di output viene letta dal browser, non fidandosi dell’etichetta.
Per la riga di warning, non serve alcun harness:
"/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"
Aggiornato al 2026-07-28.
Prova Thunderbit per l’estrazione di dati web
Decisione e avvertenze
Nella matrice testata, Google Chrome standard 150 ha rifiutato --disable-extensions-except insieme a --load-extension, mentre Chrome for Testing 149 e 151 hanno caricato l’estensione. Chrome ha registrato il rifiuto con severità WARNING: "--load-extension is not allowed in Google Chrome, ignoring." La formulazione supporta un’interpretazione legata alla build brandizzata, e il sandwich di versioni esclude una semplice rimozione monotona, ma build e versione restano confusi senza un ramo cross-build alla stessa versione o prove da sorgente/configurazione.
Per un harness di estensioni bloccato su una versione, usa un eseguibile del browser esplicitamente versionato e verifica sia il service worker sia il marker del content script. In questa configurazione Playwright 1.56.0, l’export dell’estensione richiedeva la cattura via CDP su directory ed è arrivato con un nome file diverso. Lo stub caricato da riga di comando ha inoltre eseguito l’iniezione sulla fixture file:// testata; altri percorsi di installazione non sono stati testati.
Prova Thunderbit per l’estrazione di dati web Get Started Free
FAQ
--load-extension è stato rimosso del tutto da Chrome?
No. Chrome for Testing 149.0.7827.55 e 151.0.7922.10 hanno entrambi caricato lo stub MV3 non impacchettato tramite quel flag e completato i sei controlli valutati. Google Chrome standard 150.0.7871.187 lo ha rifiutato e ha registrato "--load-extension is not allowed in Google Chrome, ignoring". Questo supporta, ma non dimostra, un blocco legato alla build brandizzata: il comportamento esclude una semplice rimozione monotona, mentre una regressione specifica di Chrome 150 poi corretta in 151 resta compatibile con il disegno a tre rami.
Perché non vedo alcun errore, e come distinguo “non ha mai caricato” da “ha caricato ma è fallito in silenzio”?
Il warning non viene stampato alla verbosità predefinita. Avvia con --enable-logging=stderr e compare subito; senza di esso Chrome si avvia normalmente, ma il servizio delle estensioni ignora i flag e il primo sintomo nell’harness è un timeout del selettore. Per separare “mai caricato” da un fallimento dell’iniezione, usa due segnali indipendenti: il service worker di background MV3 e un marker del content script nel DOM di destinazione. Nel ramo Chrome standard testato non compariva nessuno dei due; in entrambi i rami Chrome for Testing comparivano entrambi.
Cosa dovrei usare invece per automatizzare le estensioni?
I rami che funzionano hanno usato eseguibili Chrome for Testing bloccati via executablePath. Chromium gestito da Playwright è un altro binario possibile per l’automazione, ma non era un ramo di questo test e non andrebbe descritto come la stessa distribuzione senza verificare l’eseguibile risolto.
Perché waitForEvent('download') non si risolve mai quando l’estensione esporta un file?
In questa configurazione MV3/Playwright 1.56.0, l’evento non si è risolto e non è stato fornito alcun nome file suggerito. L’harness ha aperto una sessione CDP, chiamato Browser.setDownloadBehavior con una directory esplicita, quindi ha letto il file dal disco. Nei run testati, i byte del CSV sono rimasti intatti ma probe-export.csv è arrivato come download.csv; combinazioni più ampie di estensioni e browser non sono state testate.
Cosa non dice questo articolo — riguardo agli URL file:// e a Chrome standard in generale?
Due limiti, in direzioni opposte. I content script funzionano sugli URL file:// per le estensioni caricate da riga di comando — testato su entrambe le build Chrome for Testing, con lo script iniettato normalmente e l’ID dell’estensione riportato correttamente, quindi la tesi comune secondo cui non lo fanno (perché le estensioni non hanno accesso ai file per impostazione predefinita) è falsa per questo percorso di installazione. Servire le fixture via HTTP resta comunque la pratica migliore perché assomiglia a un target reale, non perché file:// blocchi l’iniezione. In senso opposto: niente di tutto questo dice che Chrome standard non possa eseguire estensioni. È stato misurato solo il percorso da riga di comando --load-extension. L’installazione .crx impacchettata, il caricamento in modalità sviluppatore e le policy enterprise con allowlist non sono stati testati, e non viene fatta alcuna affermazione su di essi. Il perimetro è la coppia di flag che i tutorial di automazione ti dicono di usare.


