Documentation
¶
Overview ¶
Package browser is the OPTIONAL real-browser engine for gosearch: it drives an unmodified Chromium-family browser (Chrome, Edge, Chromium, or Google's chrome-headless-shell) over CDP to run searches and extract page content where plain HTTP cannot — most notably pages that only render or unlock behind JavaScript.
It is a separate Go module on purpose: depending on it pulls in chromedp and, potentially, a ~100–300 MB browser runtime. The core gosearch module stays dependency-light; nothing here is imported unless you ask for it.
Honest limitations (the line this project will not cross): the browser is driven UNMODIFIED — no stealth patches, no navigator.webdriver masking, no fingerprint spoofing. The only identity adjustment is a standard desktop Chrome User-Agent string (same policy as the core HTTP client); webdriver stays on and everything else stays stock. That means the engine clears JavaScript-gated pages but does NOT defeat IP-reputation blocks or interactive CAPTCHAs. When an engine still refuses to serve results, this package reports ErrChallenge/ErrBlocked-wrapped errors like the rest of gosearch instead of pretending otherwise.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrDownloadDisabled = errors.New("browser: download disabled and no executable available")
ErrDownloadDisabled is returned when the caller explicitly opted OUT of downloading (AllowDownload(false)) but no system browser was found either, or when an embed-mode build was requested but the engine archive is absent.
var ErrNoBrowserFound = errors.New("browser: no chromium-family executable found")
ErrNoBrowserFound is returned by New when no usable Chromium-family executable was discovered on the system, none was supplied via WithExecutable, and downloads are not enabled. The error text names every location that was probed so the fix (install Chrome/Chromium/Edge, pass a path, or enable downloads) is obvious.
Functions ¶
func CurrentPlatform ¶
func CurrentPlatform() string
CurrentPlatform names the chrome-for-testing platform slug for this host (linux64, mac-arm64, mac-x64, win64), or "" when unsupported.
func DownloadFile ¶
DownloadFile streams url into dstFile atomically (.part then rename).
func Install ¶
Install performs the same discovery-or-download resolution as New without constructing an Engine: use it during deployment or image building (Dockerfile RUN step, setup script) so the one-time engine download is not paid by a live user request later. It is safe to call repeatedly — an already-present executable or cached engine short-circuits to nil.
Types ¶
type Engine ¶
type Engine struct {
// contains filtered or unexported fields
}
Engine is one long-lived, lazily started browser instance shared across calls: a single process with a single tab keeps steady-state memory at roughly one page's worth instead of paying full startup per request.
func New ¶
New resolves which executable to drive (explicit path > embedded archive > system discovery > opt-in download) and returns an Engine. The browser process starts lazily on first use, not in New, so constructing one never pays startup cost. Call Close when done.
func (*Engine) Close ¶
Close shuts the browser down. Throwaway profile directories are removed; user-supplied persistent ones (WithProfileDir) are kept — that is the whole point of them. Idempotent.
func (*Engine) Executable ¶
Executable reports the resolved chromium-family binary path. Valid before first use because resolution happens in New.
func (*Engine) Fetch ¶
Fetch retrieves url in the shared tab, waits for JavaScript to render it, and extracts the readable main content into a gosearch.Page — a drop-in swap for gosearch.Fetch for callers whose target pages need JS.
The extractor prefers <article>/<main>, falls back to the text-heaviest container heuristic, strips script/style/nav/header/footer/aside/form noise, and caps output at ~20k characters. It is deliberately simpler than the core module's DOM-based readability extractor: rendered innerText has already discarded most chrome, so heavy scoring buys little here.
func (*Engine) Search ¶
Search renders Google for query in the shared tab and extracts results from the DOM AFTER JavaScript has run — the case plain HTTP cannot handle.
The heuristic is best-effort exactly like the core providers: every anchor containing an <h3> is treated as a result candidate, titles come from the h3, snippets from the surrounding result container's text with the title line removed. Non-http(s) destinations, Google-internal plumbing (search pagination, accounts, support, /url wrappers) and duplicates are skipped. When no h3 ever appears (consent wall, captcha, unusual layout), Search returns an error wrapping gosearch.ErrChallenge rather than empty results, so callers can distinguish "no answers" from "engine refused".
type Option ¶
type Option func(*engineConfig)
Option configures an Engine. Options are applied in order.
func AllowDownload ¶
AllowDownload permits New to download chrome-headless-shell — a small, official, automation-only build of Chromium published on Google's chrome-for-testing CDN — into the OS user cache directory the first time it is needed. Nothing is ever downloaded without this explicit opt-in.
func WithCacheDir ¶
WithCacheDir overrides where the downloaded or embedded engine is stored and extracted (default: the OS user cache directory, e.g. ~/.cache/gosearch/browser on Linux). Useful when the default location is read-only, as in some locked-down containers.
func WithExecutable ¶
WithExecutable bypasses all discovery and uses the given chromium-family executable (Chrome, Chromium, Edge, or chrome-headless-shell) as-is.
func WithHeadless ¶
WithHeadless controls whether the browser runs headlessly (default true, i.e. headless). WithHeadless(false) opens a visible window — useful once, with WithProfileDir, to manually clear an interactive challenge so the saved session carries over to later headless runs.
func WithProfileDir ¶
WithProfileDir uses a persistent browser profile at path: cookies survive Close() and across runs. The directory is created if missing and is NOT deleted by Close.
func WithUserAgent ¶
WithUserAgent sets the exact User-Agent string the browser declares. By default chrome-headless-shell advertises "HeadlessChrome", which search engines treat as an automation-only build and answer differently; the default here is a standard desktop Chrome UA instead — the same realistic-identity policy the core HTTP client already applies. Nothing else about the browser is altered: webdriver stays on, fingerprints stay stock, CAPTCHAs are never solved.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
headed-once
command
Command headed-once opens a VISIBLE browser window with a persistent profile so YOU can manually clear an interactive challenge (CAPTCHA / consent) one time; the saved session then carries over to headless runs of examples/search using the same profile directory.
|
Command headed-once opens a VISIBLE browser window with a persistent profile so YOU can manually clear an interactive challenge (CAPTCHA / consent) one time; the saved session then carries over to headless runs of examples/search using the same profile directory. |
|
search
command
Command search runs a headless Google search through the browser engine and prints results.
|
Command search runs a headless Google search through the browser engine and prints results. |
|
tools
|
|
|
fetch-engine
command
Command fetch-engine downloads the stable chrome-headless-shell archive for the current platform into engine/chrome-headless-shell.zip so a build with -tags gosearch_embed_engine can embed it.
|
Command fetch-engine downloads the stable chrome-headless-shell archive for the current platform into engine/chrome-headless-shell.zip so a build with -tags gosearch_embed_engine can embed it. |