web-scraper-server
Automatically handles Cloudflare Turnstile challenges and provides stealth-strategy matrix testing for bypassing anti-bot protections.
Provides a resilient fallback endpoint for unblockable organic search extraction when Google SERP is soft-banned.
Automatically detects Google Search (SERP) requests and applies specialized Native Chrome Hardware Spoofing bypass to prevent rate-limiting bans.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@web-scraper-server scrape https://example.com and export as markdown"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Web Scraper Toolkit
Expertly crafted by Roy Dawson IV
Use Case Synopsis
Web Scraper Toolkit is a production-grade scraping and browser automation platform for:
Engineers and analysts who need repeatable, scriptable web extraction.
Red/blue team workflows that need transparent anti-bot diagnostics and safe automation controls.
Agent builders who need MCP tools for autonomous URL ingestion, crawling, extraction, and post-processing.
You can run it as:
A CLI tool (
web-scraper)An MCP server (
web-scraper-server)A Python library (typed config + async APIs)
Related MCP server: MultiZen MCP Server
What it does (without reading code)
Core scraping and extraction
Single-page scrape, batch scrape, and domain crawling.
Sitemap ingestion and tree extraction.
Markdown, text, HTML, JSON, XML, CSV, screenshot, and PDF outputs.
Contact extraction (emails, phones, socials).
Browser intelligence and anti-bot handling
Playwright-first automation with stealth profile controls.
Native browser fallback routing (
chrome,msedge,chromium) when blocked.Interactive browser MCP tools for navigate/click/type/wait/key/scroll/hover/evaluate/screenshot.
Compact interaction-map MCP output for LLM-friendly clickable-element discovery.
Optional accessibility-tree MCP output for role/name-first autonomous navigation.
Script-level diagnostics for detection analysis and route optimization.
Dynamic host learning (auto-routing)
Per-domain host profiles in
host_profiles.json.Safe-subset auto-learning of routing strategy.
Promotion only after clean incognito successes (default threshold: 2).
Deterministic precedence: explicit override > host profile > global config > defaults.
Out-of-the-box behavior ("just works")
Default behavior is tuned for safety + resilience:
Playwright Chromium is the default primary browser path.
Incognito-style contexts by default.
Native fallback policy defaults to
on_blocked.Host profile learning is enabled by default.
Host profile read-only mode is available (
host_profiles_read_only=true) to apply-only with no writes.Host profile store is auto-created when needed.
If host profile persistence cannot initialize, toolkit continues with clear diagnostic metadata.
OS-level anti-bot interaction is blocked in headless mode.
Before OS mouse takeover, toolkit warns the operator and verifies active foreground window.
Cloudflare Turnstile challenges are handled autonomously by dynamically disabling detection-vulnerable stealth scripts to allow native auto-validation.
Google Search (SERP) requests are automatically detected and routed through a specialized Native Chrome Hardware Spoofing bypass block to prevent
429 Too Many Requests (sorry/index)bans.If Google enforces a persistent soft-ban, the toolkit transparently falls back to the resilient DuckDuckGo HTML endpoint to guarantee unblockable organic search extraction.
Quick Start (60 seconds)
pip install web-scraper-toolkit
playwright installOptional desktop solver support:
pip install web-scraper-toolkit[desktop]
playwright installRun a first scrape:
web-scraper --url https://example.com --format markdown --exportEnd-to-End Flow
Simple flow

Advanced flow (dynamic routing)

These diagrams are rendered from Mermaid source files for GitHub/PyPI compatibility. Sources:
docs/diagrams/*.mmd
How to Use It
1) CLI (fastest entry)
Minimal:
web-scraper --url https://example.com --format markdown --exportBatch + merge:
web-scraper --input urls.txt --workers auto --format text --merge --output-name merged.txtDiagnostics wrapper:
web-scraper --run-diagnostic challenge_matrix --diagnostic-url https://target-site.tld/resource --diagnostic-runs-per-variant 2Optional toolkit auto-commit (off by default):
web-scraper --run-diagnostic toolkit_route --diagnostic-url https://target-site.tld/resource --diagnostic-auto-commit-host-profileStrict progression gating + artifact capture:
web-scraper \
--run-diagnostic toolkit_route \
--diagnostic-url https://target-site.tld/resource \
--diagnostic-require-2xx \
--diagnostic-save-artifacts \
--diagnostic-artifacts-dir ./scripts/out/artifactsDeterministic fixture replay / recording for regression analysis:
python scripts/diag_toolkit_route.py --fixture-replay ./tests/fixtures/challenge/cloudflare_blocked.json
python scripts/diag_toolkit_route.py --url https://target-site.tld/resource --fixture-record ./tests/fixtures/challenge/latest_toolkit_fixture.json
python scripts/diag_challenge_matrix.py --fixture-replay ./tests/fixtures/challenge/zoominfo_px_then_cf_loop.jsonCloudflare stealth-strategy matrix testing:
python scripts/diag_cloudflare_matrix.py --url https://target-site.tld/challenge2) MCP (agentic mode)
Local stdio:
web-scraper-server --stdioRemote transport:
web-scraper-server --transport streamable-http --host 127.0.0.1 --port 8000 --path /mcp3) Python API
import asyncio
from web_scraper_toolkit.browser.config import BrowserConfig
from web_scraper_toolkit.browser.playwright_handler import PlaywrightManager
async def main() -> None:
cfg = BrowserConfig.from_dict({
"headless": True,
"browser_type": "chromium",
"native_fallback_policy": "on_blocked",
"host_profiles_enabled": True,
"host_profiles_path": "./host_profiles.json",
"host_profiles_read_only": False,
})
async with PlaywrightManager(cfg) as manager:
content, final_url, status = await manager.smart_fetch("https://example.com")
print({"status": status, "url": final_url, "has_content": bool(content)})
asyncio.run(main())Safety Model (OS input + anti-bot interactions)
When toolkit enters OS-level mouse challenge solving:
It warns the operator before input takeover.
It validates that the browser is foreground/active.
It verifies click/hold coordinates are inside active window bounds.
It refuses OS interaction in headless mode.
pyautoguifailsafe remains active (move cursor to a screen corner to abort).
Optional env override:
WST_OS_INPUT_WARNING_SECONDS(default:3)
Configuration Model
Precedence order:
Explicit CLI/MCP arguments
Environment variables (
WST_*)settings.local.cfg/settings.cfgconfig.jsonBuilt-in defaults
Key files:
config.example.jsonsettings.example.cfghost_profiles.example.jsonINSTRUCTIONS.md(full operations runbook)
Full Usage and Operations
For exhaustive setup, deployment, troubleshooting, CLI/MCP option coverage, and diagnostics workflows, read:
INSTRUCTIONS.mddocs/config_schema.md(config + host profile schema contract)docs/api_stability.md(API/deprecation policy)docs/support_matrix.md(platform/browser support matrix)docs/release_checklist.md(ship checklist)
Canonical script diagnostics now use scripts/diag_*.py names.
Truthfulness note:
challenge diagnostics now classify pages from visible text + structure, not raw HTML noise
fixture replay is browserless and safe for deterministic regression checks
live smoke results may still fail when a target changes, but the toolkit now reports those failures more accurately
Verified Outputs
The following output blocks are copied from deterministic command runs in this repository.
Verified Output A — diag_toolkit_zoominfo --help
Command:
python scripts/diag_toolkit_zoominfo.py --helpExpected output:
usage: diag_toolkit_zoominfo.py [-h] [--url URL] [--timeout-ms TIMEOUT_MS]
[--skip-interactive]
[--include-headless-stage]
[--log-level {DEBUG,INFO,WARNING,ERROR}]
[--auto-commit-host-profile]
[--host-profiles-path HOST_PROFILES_PATH]
[--read-only] [--require-2xx]
[--save-artifacts]
[--artifacts-dir ARTIFACTS_DIR]Verified Output B — CLI includes strict/artifact diagnostic flags
Command:
python -m web_scraper_toolkit.cli --helpExpected excerpt:
--diagnostic-require-2xx
Require final HTTP 2xx status for toolkit diagnostic
stage success.
--diagnostic-save-artifacts
Persist per-stage diagnostic artifacts for toolkit
route diagnostics.
--diagnostic-artifacts-dir DIAGNOSTIC_ARTIFACTS_DIR
Optional artifacts directory override for toolkit
route diagnostics.Verified Output C — mocked diagnostic report payload (from deterministic test)
File/fixture expectation used in tests/test_script_diagnostics.py:
{
"summary": {
"progressed_stages": 1
}
}Production Deployment Checklist
Before release tags, execute and verify:
ruff format --check .
ruff check src
mypy
pytest -q -m "not integration"
python -m build
python -m twine check dist/*
python scripts/clean_workspace.py --dry-runFor full release/security gates, see docs/release_checklist.md.
Support Matrix
Python: 3.10–3.13
OS: Windows, Linux, macOS
Native fallback channels: chrome, msedge, chromium
Interactive OS-level challenge solving: headed desktop sessions only
Details and limitations: docs/support_matrix.md.
Author & Links
Created by: Roy Dawson IV
GitHub: https://github.com/imyourboyroy
PyPi: https://pypi.org/user/ImYourBoyRoy/
Host Profile Operator CLI
Host-learning now has an explicit operator CLI so you can inspect, diff, and manage learned routing without digging through JSON manually.
web-scraper-hosts --path ./host_profiles.json summary
web-scraper-hosts --path ./host_profiles.json inspect zoominfo.com
web-scraper-hosts --path ./host_profiles.json diff zoominfo.com
web-scraper-hosts --path ./host_profiles.json promote zoominfo.com
web-scraper-hosts --path ./host_profiles.json demote zoominfo.com
web-scraper-hosts --path ./host_profiles.json reset zoominfo.comJSON output is available for automation:
web-scraper-hosts --path ./host_profiles.json --json inspect zoominfo.comThis keeps host-learning mutations explicit:
inspect/diff/summaryare read-onlypromote/demote/resetmutate the store intentionally
Available Tools
62 toolsbatch_contactsA
Extract contacts from multiple URLs in parallel.
Uses hardware-limited concurrency (CPU cores - 1) for optimal performance.
Inputs: urls (required), timeout_profile. Returns: result
batch_scrapeC
Scrape multiple URLs in parallel.
Inputs: urls (required), format, workers, timeout_profile. Returns: result
browser_accessibility_treeA
Return a trimmed Playwright accessibility snapshot. Best for role/name-driven navigation on dynamic SPAs.
Inputs: selector, max_nodes, max_text_length, interesting_only. Returns: result
browser_clickA
Click an element on the current page by CSS selector. Returns updated page state after the click. Requires an active browser session (call browser_navigate first).
Inputs: selector (required). Returns: result
browser_closeA
Close the interactive browser session and free resources. Call this when done with interactive browsing.
Inputs: no named parameters. Returns: result
browser_evaluateA
Run a JavaScript expression on the current page and return the result. Useful for extracting data, checking page state, or triggering actions. Example: browser_evaluate("document.querySelectorAll('a').length")
Inputs: js_expression (required). Returns: result
browser_get_elementsA
Find elements matching a CSS selector on the current page. Returns up to 50 elements with tag, text, and href attributes. Useful for discovering clickable links, buttons, or form elements.
Inputs: selector (required). Returns: result
browser_get_interaction_mapB
Return a compact map of interactive elements with selector hints. Optimized for LLM context windows on dynamic pages.
Inputs: selector, max_elements, include_hidden. Returns: result
browser_hoverA
Hover over an element by CSS selector. Useful for menus and tooltips rendered on hover.
Inputs: selector (required). Returns: result
browser_press_keyC
Press a keyboard key (Enter, Escape, Tab, ArrowDown, etc.). Optionally focus a selector before pressing.
Inputs: key (required), delay_ms, selector. Returns: result
browser_read_pageA
Read the content of the current page or a specific element. Format: 'text' (default), 'html'. Selector: Optional CSS selector to read a specific element. Returns page state with content field.
Inputs: format, selector. Returns: result
browser_screenshotA
Capture a screenshot of the current page. Returns base64-encoded PNG image data.
Inputs: no named parameters. Returns: result
browser_scrollA
Scroll page content or a specific scrollable element. Supports directions: up, down, left, right.
Inputs: amount, smooth, selector, direction. Returns: result
browser_solve_challengeA
Explicitly trigger challenge detection and solving on the current page. Solves Cloudflare Turnstile, Cloudflare spatial, and PerimeterX Press & Hold. Returns page state with challenges_solved flag.
Inputs: no named parameters. Returns: result
browser_typeA
Type text into an input field on the current page. The selector should target an input, textarea, or contenteditable element. Returns updated page state.
Inputs: text (required), selector (required). Returns: result
browser_wait_forA
Wait for selector state or a fixed delay on the active page. Use this for SPA flows where UI updates are asynchronous.
Inputs: state, selector, timeout_ms. Returns: result
cancel_jobC
Cancel a running async job.
Inputs: job_id (required). Returns: result
chunk_textA
Split text into overlapping chunks for LLM processing. Useful for processing content that exceeds context limits.
Inputs: text (required), overlap, max_chunk_size. Returns: result
clear_cacheA
Clear the response cache. Use when cached data may be stale.
Inputs: no named parameters. Returns: result
clear_historyA
Clear scraping history.
Inputs: no named parameters. Returns: result
clear_host_profileB
Delete one host profile record from the profile store.
Inputs: host (required). Returns: result
clear_sessionA
Clear a browser session (cookies, storage). Use for fresh starts.
Inputs: session_id. Returns: result
click_elementA
Navigate to URL and click an element (for JS triggers, expanding sections).
Inputs: url (required), selector (required), timeout_profile. Returns: result
configure_host_learningC
Configure host-profile auto-learning behavior.
Inputs: enabled, threshold, apply_mode, profiles_path. Returns: result
configure_retryC
Configure retry behavior with exponential backoff.
Inputs: max_delay, max_attempts, initial_delay. Returns: result
configure_runtimeC
Apply runtime override values without restarting the MCP server.
Inputs: overrides_json (required). Returns: result
configure_scraperD
Configure browser settings.
Inputs: headless, timeout_ms, browser_type, host_profiles_path, +14 more. Returns: result
configure_stealthC
Configure stealth mode and robots.txt compliance.
Inputs: stealth_mode, respect_robots. Returns: result
crawl_siteC
Crawl a site's sitemap to discover pages.
Inputs: url (required), timeout_profile. Returns: result
deep_researchC
Perform Deep Research (Search + Crawl + Report).
Inputs: query (required), timeout_profile. Returns: result
detect_content_typeC
Detect content type of URL (HTML, PDF, image, etc.).
Inputs: url (required), timeout_profile. Returns: result
download_fileC
Download file from URL. Saves PDFs, images, documents directly.
Inputs: url (required), path (required), timeout_profile. Returns: result
extract_contactsB
Extract all contact information from a URL.
Returns structured JSON with emails, phones, socials, and detected names.
Inputs: url (required), timeout_profile. Returns: result
extract_linksB
Extract all hyperlinks from a webpage.
Inputs: url (required), filter_external, timeout_profile. Returns: result
extract_tablesC
Extract structured table data from webpage.
Inputs: url (required), table_selector, timeout_profile. Returns: result
fill_formB
Fill and submit a web form. Supports login automation.
Inputs: url (required), fields (required), save_session, session_name, +2 more. Returns: result
get_cache_statsA
Get response cache statistics (hits, misses, size).
Inputs: no named parameters. Returns: result
get_configB
Get current configuration settings.
Inputs: no named parameters. Returns: result
get_historyC
Get recent scraping history.
Inputs: limit. Returns: result
get_host_profilesB
Return host profile learning store (all hosts or one host).
Inputs: host. Returns: result
get_metadataB
Extract semantic metadata (JSON-LD, OpenGraph, TwitterCards).
Inputs: url (required), timeout_profile. Returns: result
get_sitemapB
Smart Sitemap Discovery and Filtering. Use 'keywords' to filter (e.g. 'team', 'about' for finding people pages).
Inputs: url (required), limit, keywords, timeout_profile. Returns: result
get_token_countB
Estimate token count for text. Helps manage LLM context limits.
Inputs: text (required), model. Returns: result
health_checkA
Check system health. Returns status of browser, cache, sessions.
Inputs: no named parameters. Returns: result
list_jobsC
List recent async jobs and their statuses.
Inputs: limit. Returns: result
list_sessionsA
List all saved browser sessions.
Inputs: no named parameters. Returns: result
new_sessionA
Start a fresh browser session, clearing all existing sessions.
Inputs: no named parameters. Returns: result
poll_jobB
Get current status of a job started by start_job.
Inputs: job_id (required), include_result. Returns: result
reload_runtime_configC
Reload runtime settings from config files.
Inputs: config_path, local_config_path. Returns: result
run_bot_surface_diagnosticC
Run script-level bot surface diagnostics (scripts/bot_check.py).
Inputs: modes, sites, browsers, headless, +5 more. Returns: result
run_browser_info_diagnostic_toolC
Collect browser fingerprint telemetry via scripts/get_browser_info.py.
Inputs: extra_args, save_to_file. Returns: result
run_challenge_diagnosticB
Run target-site diagnostics in either toolkit-native or matrix smoking-gun mode. mode=toolkit -> scripts/diag_toolkit_route.py mode=matrix -> scripts/challenge_diagnostic_matrix.py
Inputs: url, mode, browser, headless, +17 more. Returns: result
run_playbookC
Execute an Autonomous Crawl using a Playbook.
Inputs: playbook_json (required), proxies_json, timeout_profile. Returns: result
save_pdfC
Save a URL as a PDF file.
Inputs: url (required), path (required), timeout_profile. Returns: result
scrape_urlB
Scrape a URL and return its content. Primary tool for content acquisition.
Inputs: url (required), format, selector, max_length, +1 more. Returns: result
screenshotC
Capture a screenshot of a webpage.
Inputs: url (required), path (required), timeout_profile. Returns: result
search_webC
Perform a web search and return results.
Inputs: query (required), timeout_profile. Returns: result
set_host_profileB
Set active host routing profile from JSON payload (admin override).
Inputs: host (required), profile_json (required). Returns: result
start_jobA
Start a long-running job and return immediately with a job_id.
Supported job types: batch_scrape, deep_research, run_playbook, batch_contacts.
Inputs: job_type (required), payload_json (required), timeout_profile. Returns: result
truncate_textA
Truncate text to fit within token limit. Preserves sentence boundaries when possible.
Inputs: text (required), model, max_tokens. Returns: result
validate_urlA
Validate URL reachability before scraping. Returns status, content type, size.
Inputs: url (required), timeout_profile. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 62 tools
Multiple overlapping tool pairs exist, such as `screenshot` vs `browser_screenshot`, `click_element` vs `browser_click`, `get_sitemap` vs `crawl_site`, and `save_pdf` vs `download_file`. The split between browser-based and non-browser-based workflows adds confusion, forcing agents to choose between near-equivalent tools based on session state.
Tool names are predominantly snake_case with a verb_noun convention (`scrape_url`, `get_metadata`, `list_jobs`). The `browser_` prefix provides a consistent subgroup, and most deviations are minor (e.g., `health_check` instead of `check_health`). Long diagnostic tool names are slightly awkward but still follow the general pattern.
With 62 tools, the server far exceeds a coherent scope. Many tools are highly specialized diagnostics or configuration variants that could be consolidated. The sheer volume makes the surface overwhelming and dilutes the clarity of the core scraping workflow.
The tool set covers the full web scraping lifecycle: URL validation, fetching, content extraction, crawling, browser automation, job scheduling, configuration, caching, session management, and diagnostics. No major scraping capability appears to be missing, making the server functionally comprehensive.
Maintenance
Related MCP Connectors
Web scraping, browser automation, screenshots and AI data extraction for AI agents via MCP.
One MCP for the Web. Easily search, crawl, navigate, and extract websites without getting blocked.…
Crawl, scrape, search the web, and automate browsers at scale with anti-bot bypass.
Cloud browser, web extraction, screenshots, and remote CDP tools for AI agents.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceProvides a real browser that bypasses bot detection (Cloudflare, Turnstile) for AI agents, enabling navigation, clicking, typing, screenshots, and data collection through MCP tools.166 npmMIT
- FlicenseNot gradedqualityAmaintenanceEnables AI agents and human operators to drive isolated browser profiles with persistent cookies, fingerprints, and proxies, exposing navigation, clicking, typing, extraction, screenshots, JS evaluation, tabs, cookies, and waits to MCP clients.-
- AlicenseNot gradedqualityAmaintenanceEnables MCP-compatible AI agents to control an anti-detection browser for navigation, interaction, search, extraction, downloads, multi-tab workflows, and reusable sessions. It provides a practical browser automation toolset for automated web tasks while reducing blocking risks.899 npmMIT
- AlicenseNot gradedqualityAmaintenanceEnables MCP-compatible AI agents to automate web browsing with anti-detection behavior, including navigation, interaction, search, extraction, downloads, multi-tab workflows, and reusable sessions.899 npmMIT