Skip to main content
Glama
web-scraper-server

web-scraper-server

by ImYourBoyRoy

Web Scraper Toolkit

PyPI - Version PyPI - Python Version GitHub License GitHub Actions Workflow Status Ruff MCP Ready

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:

  1. A CLI tool (web-scraper)

  2. An MCP server (web-scraper-server)

  3. 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 install

Optional desktop solver support:

pip install web-scraper-toolkit[desktop]
playwright install

Run a first scrape:

web-scraper --url https://example.com --format markdown --export

End-to-End Flow

Simple flow

Simple flow diagram

Advanced flow (dynamic routing)

Advanced routing flow diagram

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 --export

Batch + merge:

web-scraper --input urls.txt --workers auto --format text --merge --output-name merged.txt

Diagnostics wrapper:

web-scraper --run-diagnostic challenge_matrix --diagnostic-url https://target-site.tld/resource --diagnostic-runs-per-variant 2

Optional toolkit auto-commit (off by default):

web-scraper --run-diagnostic toolkit_route --diagnostic-url https://target-site.tld/resource --diagnostic-auto-commit-host-profile

Strict 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/artifacts

Deterministic 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.json

Cloudflare stealth-strategy matrix testing:

python scripts/diag_cloudflare_matrix.py --url https://target-site.tld/challenge

2) MCP (agentic mode)

Local stdio:

web-scraper-server --stdio

Remote transport:

web-scraper-server --transport streamable-http --host 127.0.0.1 --port 8000 --path /mcp

3) 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.

  • pyautogui failsafe remains active (move cursor to a screen corner to abort).

Optional env override:

  • WST_OS_INPUT_WARNING_SECONDS (default: 3)


Configuration Model

Precedence order:

  1. Explicit CLI/MCP arguments

  2. Environment variables (WST_*)

  3. settings.local.cfg / settings.cfg

  4. config.json

  5. Built-in defaults

Key files:

  • config.example.json

  • settings.example.cfg

  • host_profiles.example.json

  • INSTRUCTIONS.md (full operations runbook)


Full Usage and Operations

For exhaustive setup, deployment, troubleshooting, CLI/MCP option coverage, and diagnostics workflows, read:

  • INSTRUCTIONS.md

  • docs/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 --help

Expected 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 --help

Expected 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-run

For 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.


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.com

JSON output is available for automation:

web-scraper-hosts --path ./host_profiles.json --json inspect zoominfo.com

This keeps host-learning mutations explicit:

  • inspect / diff / summary are read-only

  • promote / demote / reset mutate the store intentionally

Available Tools

62 tools
batch_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_navigateA

Navigate the interactive browser to a URL. Auto-detects and solves Cloudflare and PerimeterX challenges. Returns page state (url, title, status). Creates a new session if none exists.

Inputs: url (required), wait_until. 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_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

    C2.8/5.0

    Scored across 62 tools

    Disambiguation2/5

    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.

    Naming Consistency4/5

    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.

    Tool Count1/5

    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.

    Completeness5/5

    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

    ActivityNo data
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      Provides a real browser that bypasses bot detection (Cloudflare, Turnstile) for AI agents, enabling navigation, clicking, typing, screenshots, and data collection through MCP tools.
      166 npm
      MIT
    • F
      license
      Not graded
      quality
      A
      maintenance
      Enables 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.
      -
    • A
      license
      Not graded
      quality
      A
      maintenance
      Enables 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 npm
      MIT