Skip to main content

headless-fallback

Use when a static fetch returns nothing useful and the page needs a real browser. Covers `--browser-mode auto|always|never`, external CDP via `--browser-endpoint`, symptoms of JS-only pages and WAF blocks, and the performance cost.

ソース情報

リポジトリ
xberg-io/crawlberg
ソースの最終更新活動
2026年10月6日 20:29
検出された SKILL.md の言語
英語
スター
182
フォーク
28

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
headless-fallback
description
Use when a static fetch returns nothing useful and the page needs a real browser. Covers `--browser-mode auto|always|never`, external CDP via `--browser-endpoint`, symptoms of JS-only pages and WAF blocks, and the performance cost.
<!-- AI-RULEZ :: GENERATED FILE — DO NOT EDIT Content-Hash: blake3:9ce8ead27ee0f0b76d36ce4a455a5d17936077d6582e737c9b9a7ba46819b686 Source-Hash: blake3:b696646d260848111b4456bd8e7a28ce2bb42f9108461a50bb23d3dc1f8d8608 Schema-Version: v1 --> # Headless fallback Some pages are unscrapable without a real browser — SPA shells, infinite scroll, Cloudflare interstitials, JS-rendered article bodies. Crawlberg ships with an optional headless-Chrome backend driven by chromiumoxide. ## Modes ```text --browser-mode auto # default — try static first, fall back to browser on JS/WAF --browser-mode always # skip static, go straight to browser --browser-mode never # static only, fail closed ``` ### `auto` (default) The engine fetches statically, then inspects the response. It launches headless Chrome and re-fetches when it sees: - WAF responses from one of 8 detected vendor fingerprints (Cloudflare, Akamai, AWS WAF, Imperva, DataDome, PerimeterX, F5, plus a generic catch-all). - SPA shells: `<noscript>` warnings, near-empty `<body>` with heavy JS. - Heuristic JS-render-required signals. This is the right default. The browser only spins up when needed. ### `always` Skip the static probe entirely. Use when: - The user already told you the page needs JS. - You are scraping a site you know is React/Vue/Svelte SPA. - You need `<script>`-emitted state that never lands in static HTML. ```bash crawlberg scrape https://spa.example.com --browser-mode always --format markdown ``` ### `never` Static only — the browser path is disabled. Use when: - You are in a hot loop where a stray Chrome launch would blow the budget. - You are running in a sandbox without a Chrome binary. - The user explicitly wants only static fetches. In `never` mode, JS-only pages return empty/stub content. Inspect `markdown.content` and `markdown.warnings` before treating the result as final. ## Symptoms that point to headless In `--browser-mode never` or when you suspect the auto detector missed a signal: - `markdown.content` is short, nav-only, or just a loading message. - `status_code` is 200 but `metadata.headings` is empty on a page that clearly has headings. - `markdown.warnings` mentions JS-render-required or WAF detection. - 403/406/503 with WAF response headers (`server: cloudflare`, `cf-mitigated`, `x-amz-cf-id`, `set-cookie: __cf_bm=…`). Re-run with `--browser-mode always`. If that succeeds, leave it set for that host. ## External CDP endpoint Point at an already-running Chrome (Browserless, Steel, your own) instead of launching locally: ```bash crawlberg scrape https://example.com \ --browser-mode always \ --browser-endpoint ws://browser.internal:9222/devtools/browser/<id> \ --format markdown ``` The endpoint must be a WebSocket URL — `ws://` or `wss://`. The CLI rejects anything else with a clear error. Use external CDP when: - You are running in containers or CI without a local Chrome. - You want a shared, warm browser pool across many crawl jobs. - You need browser-side residential proxies or stealth configuration the local Chrome cannot provide. ## Performance cost Headless Chrome is expensive relative to a static fetch: - Cold start: 1-3 seconds the first time it launches. - Per-page overhead: 500 ms-2 s for `NetworkIdle` wait, plus the page's own JS load time. - Memory: each tab takes 100-300 MB; long crawls should bound `--concurrent`. Mitigations: - Stay in `--browser-mode auto` — the engine only pays the cost when it needs to. - Use `--browser-endpoint` to share one warm browser across jobs. - Drop `--concurrent` when you know the crawl will route through Chrome. ## Wait strategies Pass via `--config` JSON when you need control: ```bash crawlberg scrape https://example.com --browser-mode always \ --config '{"browser":{"wait":"selector","wait_selector":".article-body"}}' ``` Supported strategies (the `browser.wait` field is a string enum; pair `"selector"` with a sibling `wait_selector`): - `network_idle` (default) — wait until the network goes quiet. - `selector` — wait until the CSS selector in `wait_selector` resolves. - `fixed` — wait a fixed duration. `extra_wait` adds milliseconds on top of the wait strategy if the page keeps loading content after the primary signal. ## Persistent profiles ```bash crawlberg scrape https://app.example.com --browser-mode always \ --config '{"browser_profile":"prod","save_browser_profile":true}' ``` Profile names are path-traversal-validated. Use them to keep cookies, localStorage, and login state across runs without re-authenticating.
GitHubで見る