Skip to main content

scrapper-tool

A reusable Python web-scraping toolkit — production-grade primitives, anti-bot ladder, fixture-replay testing.

Built from the scraping core behind PartsPilot, extracted as an open-source library so other projects (and LLM agents) can pick up the same patterns without redoing the reverse-engineering work.


CI PyPI version Python versions Downloads License: MIT Code style: ruff Type-checked: mypy PRs Welcome GitHub Stars GitHub Forks

Quickstart · All docs · Settings · MCP · Docker · Changelog


Status (2026-08-29): stable (v3.1.1). The public Python API and MCP tool surface are SemVer-stable.

v3.1.0 migrates the MCP server to the 2.x SDK (FastMCPMCPServer), lifting the mcp<2 cap deferred from 3.0.0. No public Python API or MCP tool changed; the breaking part is the dependency floor, mcp>=2.1.1,<3 on the [agent] extra, which will not co-install with a mcp 1.x pin. It also fixes both docker-compose MCP services, which inherited the REST entrypoint and so never spoke MCP at all.

v3.0.0 adds a target URL guard that vets every URL before a request is issued — private, loopback and cloud-metadata targets are refused, and that is on by default, which is the breaking part. It also gives the captcha grid tier its own vision model, blocks page-initiated SSRF in the render tier, promotes the impersonation ladder to chrome150, and stops overriding the impersonated User-Agent (which had been advertising scrapper-tool/0.1 beside a Chrome TLS handshake — a self-identifying mismatch).

Read the breaking-change table before upgrading. Every number in the docs is measured, including the ones that did not work; see docs/TESTING.md.

What it does

Web scraping is mostly the same work every time: pick the extraction method the site actually needs, survive the TLS fingerprint, retry sanely, and write tests that do not break the moment the vendor ships CSS. scrapper-tool packages the parts that do not change per vendor.

One call does the escalation for you — cheapest method first, climbing only when the site forces it:

from scrapper_tool import scrape

data = await scrape("https://vendor.example/product/123")

Behind that call: a TLS-impersonation ladder, a stealth browser, a local LLM, and a captcha cascade — in that order, and only as far as the site makes necessary.

Install

uv pip install "scrapper-tool[full,agent]"    # all five patterns + MCP server
camoufox fetch                                # ~300 MB, best-stealth browser

pip works too, but [full] needs uv — Scrapling and Crawl4AI pin incompatible lxml ranges and only uv honours the override that reconciles them. Lighter installs and the pip escape hatch: Install guide.

Check what actually works on your machine:

scrapper-tool doctor

It reports every tier as ok / degraded / missing with the exact command to fix each one, and exits non-zero so it works as a CI or container healthcheck.

The five patterns

Pick the one DevTools points at, or let scrape() choose.

Pattern When Cost
A — JSON API An XHR returns the data Lowest
B — Embedded JSON ld+json, __NEXT_DATA__, __NUXT__ Low
C — CSS / microdata Price is in the HTML, no JSON Medium
D — Hostile Cloudflare Turnstile, Akamai, DataDome High — real browser
E — LLM agent D is still blocked, or the page needs interaction Highest — local LLM

Full guides: patterns A–E.

Security: targets are vetted before they are fetched

Every surface checks a URL before issuing a request. Private, loopback, link-local and cloud-metadata targets are refused, along with non-http(s) schemes and hostnames that resolve into private space.

This is on by default, and it matters most if you run the REST sidecar: without it, anything that can reach the sidecar can make it fetch 169.254.169.254 and read your cloud credentials back.

To reach a legitimate internal target, allowlist it rather than turning the guard off:

SCRAPPER_TOOL_URL_GUARD_ALLOW=127.0.0.1,10.0.0.0/8

What is covered, what is not, and the fully-closed ..._STRICT mode: Target URL guard.

Run it as a service

Mode Command Docs
MCP server (Claude, Cursor, any MCP client) scrapper-tool-mcp docs/mcp.md
REST sidecar (any language, plain HTTP) scrapper-tool-serve docs/http-sidecar.md
Docker (all five patterns in one image) docker compose up docs/docker.md

Use it as an MCP server

Exposes the whole toolkit to any MCP client — Claude Code, Claude Desktop, Cursor, mcp-use, AutoGen, LangChain. Needs the [agent] extra:

uv pip install "scrapper-tool[full,agent]"

Wire it up

Add to your client's MCP config (.mcp.json for Claude Code, claude_desktop_config.json for Claude Desktop):

{
  "mcpServers": {
    "scrapper-tool": {
      "command": "scrapper-tool-mcp",
      "args": [],
      "env": {}
    }
  }
}

Restart the client and all nine tools appear, plus a skill://scrapper-tool resource carrying the tool's own operating manual. That is the whole setup for the default transport — stdio, which the client spawns and talks to over stdin/stdout.

The nine tools

Tool Use it for
auto_scrape Start here. Escalates A/B/C → D → E1 → E2 by itself and reports which tier won.
fetch_with_ladder One fetch through the TLS-impersonation ladder. extract_structured=True also parses JSON-LD.
extract_product schema.org Product+Offer out of HTML you already have.
extract_microdata_price <meta itemprop="price"> anchors out of HTML you already have.
map_site List a site's URLs from sitemaps + page links. No browser, no LLM, so it is cheap.
crawl_site Breadth-first crawl running the full cascade per page. Honours robots.txt.
agent_extract Pattern E1 — stealth render plus one LLM call. Needs [llm-agent].
agent_browse Pattern E2 — multi-step agent for logins, pagination, forms. Needs [llm-agent].
canary Which TLS fingerprint a site accepts. Diagnostics.

docs/mcp-tools.json is the generated, CI-enforced copy of this list.

Over HTTP instead of stdio

For a long-lived server that clients reach by URL:

scrapper-tool-mcp --transport streamable-http --host 0.0.0.0 --port 8000

Then point the client at http://localhost:8000/mcp. --transport sse is also supported. Each flag has an env var (SCRAPPER_TOOL_MCP_TRANSPORT, _HOST, _PORT).

In Docker, use the bundled service rather than the bare image — the image's default entrypoint is the REST sidecar, and the compose service overrides it:

docker compose --profile http up -d scrapper-tool-mcp-http

For the stdio spawn pattern in Docker (docker compose run --rm -T scrapper-tool), see docs/mcp.md.

Check it works

scrapper-tool doctor

Reports every tier as ok / degraded / missing. For a real end-to-end session that opens a JSON-RPC connection and calls all nine tools:

uv run python scripts/e2e/test_mcp_session.py

Two things that will otherwise cost you an hour: agent_browse needs a CDP-capable browser, so set SCRAPPER_TOOL_AGENT_BROWSER=patchright (the Camoufox default is Firefox, which has no CDP and fails deliberately rather than silently dropping stealth); and in Docker a host-local LLM URL must be host.docker.internal, not 127.0.0.1, which inside the container means the container.

Full reference: docs/mcp.md. Framework-specific wiring: docs/agent-integration.md.

Settings

Every knob is an env var, a constructor argument, or a per-call keyword — in that order of precedence. docs/SETTINGS.md is the canonical reference: if a setting is not there, it is not a public knob. .env.example is a drop-in starter with every variable annotated.

Architecture

flowchart TD
    A[Your scraper code or LLM agent] --> B[vendor_client / request_with_retry]
    B --> C{TLS-sensitive?}
    C -- no --> D[httpx]
    C -- yes --> E[curl_cffi ladder]
    E --> E1[chrome150] --> E2[chrome146] --> E3[safari2601] --> E4[firefox147]
    D --> F[Response]
    E4 --> F
    F --> G{Pattern}
    G -- A --> H[JSON API model]
    G -- B --> I[extruct: ld+json / next_data / nuxt]
    G -- C --> J[selectolax: microdata / CSS]
    G -- D --> K["Scrapling (Playwright + Turnstile)"]
    G -- "BlockedError + interactive" --> M["Pattern E: agent_extract / agent_browse"]
    M --> M1["Stealth browser (Camoufox / Patchright / Obscura)"]
    M1 --> M2["Local LLM (Ollama, qwen3-vl:8b)"]
    M2 --> M3["Captcha cascade (Camoufox auto → Theyka → paid)"]
    M3 --> L[Validated product data]
    H --> L
    I --> L
    J --> L
    K --> L

Documentation

Quickstart 5-minute on-ramp.
Settings reference Every env var, default, choice list. (v1.0.0+)
.env.example Drop-in starter file with every variable annotated.
E2E test plan Operator-runnable end-to-end suite — library / Docker / MCP modes against LM Studio. (v1.0.0+)
scripts/e2e/ Runnable test scripts referenced by the E2E plan.
Recon playbook DevTools-driven reverse-engineering of a new vendor site.
Pattern A — JSON API Vendor exposes an XHR / JSON endpoint.
Pattern B — Embedded JSON ld+json, __NEXT_DATA__, __NUXT__, RSC payloads.
Pattern C — CSS / microdata itemprop="price", fallback selectors.
Pattern D — Hostile Cloudflare Turnstile, Akamai EVA.
Pattern E — LLM agent Local-LLM-driven scraping for any protected site. (v1.0.0+)
Anti-bot ladder reference How the ladder walks, when to bump the primary profile.
Test helpers FakeCurlSession, replay_fixture, golden-snapshot pattern.
Agent integration MCP wiring for Claude, OpenClaw, Hermes Agent, AutoGen, LangChain. (v0.2.0+)
2026-04-30 landscape research Why these tools, sourced.

Why this exists

Most scrapers are written from scratch every time, even though 90% of the work is the same: pick the right extraction pattern, survive the TLS fingerprint, retry/backoff sanely, and write tests that don't drift the moment a site updates.

scrapper-tool packages the parts that don't change per vendor, so you only write the parts that do.

  • Pattern-first design. Five named, documented extraction patterns (A–E) — pick the one DevTools points at, skip the rest.
  • Anti-bot ladder built in. Auto-walks chrome150 → chrome146 → safari2601 → firefox147 → chrome133a when a profile gets fingerprinted.
  • Deterministic tests. Fixture-replay (FakeCurlSession, replay_fixture, golden snapshots) — no live HTTP in CI.
  • Optional hostile mode. Cloudflare Turnstile / Akamai EVA defeat path via Scrapling — opt-in extra, no Playwright bloat by default.
  • LLM-agent ready. v0.2.0+ ships an MCP server so Claude, AutoGen, LangChain, etc. can drive the scraper directly.
  • Local-LLM scraping for any protected site (v1.0.0+). Pattern E adds Camoufox + browser-use + Crawl4AI + Ollama — zero API cost, two modes (agent_extract for fast 1-call extraction, agent_browse for interactive multi-step tasks). Humanlike-behavior layer defeats DataDome.
  • Captchas solved on the way past (v2.2.0+). Five tiers, cheapest first: settle → click the checkbox → align the slider (pure geometry, no model) → read the image grid with a local VLM → paid solver. Measured live: reCAPTCHA v2 grids 3/4–4/5 with a ~27B VLM, GeeTest sliders ~20% with no model at all. reCAPTCHA v3 and AWS WAF are not solvable — they are risk scores, not puzzles, and the docs say so.
  • Clearance cookies are kept, not thrown away (v2.2.0+). A solve costs ~70 s of local inference or a paid API call; the cf_clearance it buys now survives to the next tier, and to the next run via a persisted browser profile.
  • Boring stack. httpx, curl_cffi, selectolax, extruct. No managed SaaS bundled — your code, your egress.

Roadmap

  • v0.1.0 — Core HTTP client, retry/backoff, anti-bot ladder, patterns A–D, fixture-replay test helpers.
  • v0.2.0 — MCP server for LLM agents; canary CLI for nightly fingerprint-health probes.
  • v1.0.0 — Pattern E: local-LLM-driven scraping (Camoufox + browser-use + Crawl4AI + Ollama), captcha cascade, humanlike-behavior layer, full Docker stack. Public API + MCP tool surface stable under SemVer.
  • v1.1.0 — Pluggable rate-limit / robots.txt policies; per-vendor profile presets; agent_session() warm-browser pooling; broader Pattern E backends.

See CHANGELOG.md for landed changes and open issues for what's in flight.

Contributing

PRs and issues are welcome. Every PR that meaningfully changes how we scrape lands a CHANGELOG.md row.

Contributors

Contributors

Want to see your avatar here? Check CONTRIBUTING.md and open a PR.

Acknowledgements

scrapper-tool stands on the shoulders of these projects:

  • httpx — async HTTP client
  • curl_cffi — TLS / JA3 impersonation
  • selectolax — fast HTML parsing
  • extructld+json, microdata, RDFa extraction
  • Scrapling — Playwright-based hostile-site backend

License

MIT © scrapper-tool contributors.

If scrapper-tool saves you time, consider starring the repo — it helps others find it.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

scrapper_tool-3.2.0.tar.gz (784.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

scrapper_tool-3.2.0-py3-none-any.whl (303.1 kB view details)

Uploaded Python 3

File details

Details for the file scrapper_tool-3.2.0.tar.gz.

File metadata

  • Download URL: scrapper_tool-3.2.0.tar.gz
  • Upload date:
  • Size: 784.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for scrapper_tool-3.2.0.tar.gz
Algorithm Hash digest
SHA256 693aaef4d3c5f7b30a1bf8939c4a3b0f67c4a4cc9bec4d04738abe0009d59ec3
MD5 a94029f44a8c058f1f97dee61f57094e
BLAKE2b-256 e2c92bcbed0fc501f25c906e1634f2906afd1fdb4c6570a09f1cf795f68d9746

See more details on using hashes here.

Provenance

The following attestation bundles were made for scrapper_tool-3.2.0.tar.gz:

Publisher: release.yml on ValeroK/scrapper-tool

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file scrapper_tool-3.2.0-py3-none-any.whl.

File metadata

  • Download URL: scrapper_tool-3.2.0-py3-none-any.whl
  • Upload date:
  • Size: 303.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for scrapper_tool-3.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f3e21423ff0e6180622eb1df430fa82355537cd8356e863ca1466dc0187dbbec
MD5 f20ff14a8286958ec5417aa2129079a3
BLAKE2b-256 0bb6a1bfdac99d5505dd726ff751eb509f5450dd068776b38a6149c496f4e505

See more details on using hashes here.

Provenance

The following attestation bundles were made for scrapper_tool-3.2.0-py3-none-any.whl:

Publisher: release.yml on ValeroK/scrapper-tool

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

4.3.1

2 files

4.3.0

2 files

4.2.0

2 files

4.1.0

2 files

4.0.0

2 files

This release

3.2.0 This release

2 files

3.1.1

2 files

3.1.0

2 files

3.0.0

2 files

2.2.0

2 files

2.1.0

2 files

2.0.0

2 files

1.4.2

2 files

1.1.2

2 files

1.1.1

2 files

1.1.0

2 files

1.0.0

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page