diff --git a/browser_init.go b/browser_init.go index 694603c..ae8c3f2 100644 --- a/browser_init.go +++ b/browser_init.go @@ -104,8 +104,17 @@ func initBrowser(opt BrowserOptions) (*browserInitResult, error) { if len(launchArgs) > 0 { launchOpts.Args = launchArgs } - if stealth && opt.Browser == BrowserChromium && headless { - launchOpts.Channel = playwright.String("chromium") + if opt.Browser == BrowserChromium { + channel := opt.Channel + if channel == "" && stealth && headless { + // Real Chrome sheds Playwright's bundled-Chromium fingerprint + // (build ID, uniform WebGL, HeadlessChrome residue) that + // anti-bot services increasingly flag. + channel = "chrome" + } + if channel != "" { + launchOpts.Channel = playwright.String(channel) + } } browser, err = bt.Launch(launchOpts) if err != nil { @@ -216,6 +225,9 @@ func mergeOptions(base BrowserOptions, opts []BrowserOptions) BrowserOptions { if o.Stealth != nil { base.Stealth = o.Stealth } + if o.Channel != "" { + base.Channel = o.Channel + } } return base } diff --git a/cmd/browser/pkg/browser/flags.go b/cmd/browser/pkg/browser/flags.go index 56b0f51..c248dba 100644 --- a/cmd/browser/pkg/browser/flags.go +++ b/cmd/browser/pkg/browser/flags.go @@ -46,6 +46,11 @@ var Flags = BrowserFlags{ Usage: "Disable stealth mode (anti-bot-detection evasions are enabled by default)", DefaultText: "false", }, + &cli.StringFlag{ + Name: "channel", + Usage: "Chromium channel to launch (chrome, chrome-beta, chromium, msedge). Only applies when --browser=chromium. Empty = stealth default (chrome).", + Aliases: []string{"ch"}, + }, } func FromCommand(ctx context.Context, cmd *cli.Command) (extractor.Browser, error) { @@ -83,5 +88,9 @@ func FromCommand(ctx context.Context, cmd *cli.Command) (extractor.Browser, erro opts.Stealth = extractor.Bool(false) } + if ch := cmd.String("channel"); ch != "" { + opts.Channel = ch + } + return extractor.NewBrowser(ctx, opts) } diff --git a/playwright.go b/playwright.go index 684c81a..fbdb382 100644 --- a/playwright.go +++ b/playwright.go @@ -90,6 +90,15 @@ type BrowserOptions struct { // evasions are applied automatically (launch args + init scripts). When nil, // defaults to true in NewBrowser / NewInteractiveBrowser. Stealth *bool + + // Channel selects a Chromium-family browser channel when Browser is + // BrowserChromium. Accepted values include "chrome", "chrome-beta", + // "chromium", "msedge". Empty defaults to "chrome" when stealth+headless + // (real Chrome sheds the bundled-Chromium fingerprint); otherwise falls + // back to Playwright's bundled browser. The chosen channel must be + // installed on the host (e.g. `playwright install chrome`). Ignored when + // Browser is not BrowserChromium. + Channel string } func sameSiteToPlaywright(s SameSite) *playwright.SameSiteAttribute {