Skip to content

Ctx Scrapling

ctx_scrapling -- mvp.ctx_scrapling

Cluster: Context & Retrieval | Type: component | MCP Tools: 25

Overview

Resilient web scraper with a two-tier fallback chain: Scrapling (JS rendering + anti-bot evasion) when installed, then httpx + regex HTML processing. Supports CSS selector targeting, plain-text extraction, and Markdown conversion via an internal regex transformer. Both backends honour a configurable timeout and return a structured ScrapeOutput with URL, title, content, content type, and character count.

When to use:

  • Fetching live web content for a retrieval or grounding pipeline
  • Extracting article text or documentation from URLs without a separate scraping service
  • Getting Markdown-formatted content from HTML pages for downstream LLM consumption

Outbound URL safety and deployment egress

ctx_scrapling performs SSRF-oriented URL safety checks before outbound fetches. Both the direct block and MCP fetch/crawl paths reject non-HTTP schemes, localhost, literal non-public IPs, DNS names that resolve to non-public IPs, and redirects to non-public targets. DNS failures fail closed.

This code-level guard reduces common SSRF and cloud-metadata risks, but it should not be the only control in production. Hosted or multi-user deployments should also enforce network-layer egress policy, for example blocking RFC1918 ranges, link-local metadata endpoints, loopback, and internal service networks from the container, VM, or VPC firewall layer.

Example:

from mvp.ctx_scrapling import CtxScraplingBlock, ScrapeInput

block = CtxScraplingBlock(name="scraper")
result = block.infer(ScrapeInput(url="https://example.com", extract_markdown=True))
# result.value.content → Markdown text; result.value.title → page title

Works well with: ctx_markitdown, ctx_langextract, ctx_rag

Public API

CtxScraplingDecisionError(ValueError)

The LLM did not produce a usable, validated search-rerank decision.

ScraplingRerankDecision

Validated advisory rerank verdict over a returned search-record set.

Field Type Default
ordered_indices tuple[int, ...] required
dropped_indices tuple[int, ...] ()
rationale str ''
eligible_fingerprint str ''
confidence float 0.0
degraded bool False
raw_response str ''

LLMScraplingRerankRuntime

Provider-neutral search-result-rerank runtime backed by G6's LLM caller.

Constructor:

Parameter Type Default
llm LLMCaller \| None None

Methods:

rerank(query: str, records: list[Any]) -> ScraplingRerankDecision

CtxScraplingRerankPatternRuntime

Stateless, load-bearing returned-set-ceiling enforcement.

Methods:

enforce_eligibility(decision: ScraplingRerankDecision, records: list[Any]) -> tuple[list[Any], bool, bool]

CtxScraplingPlanner

Runtime-first advisory result-rerank facade with returned-order fallback.

Constructor:

Parameter Type Default
runtime ScraplingRerankRuntime \| None None
pattern_runtime CtxScraplingRerankPatternRuntime \| None None

Methods:

rerank(query: str, records: list[Any]) -> list[Any]

ScrapeInput(BaseModel)

Input to CtxScraplingBlock.

Field Type Default
url str required
selector str ''
extract_markdown bool True
timeout_sec float 10.0
run_mode Literal['beta', 'production'] 'beta'
reviewer_signature str ''

ScrapeOutput(BaseModel)

Output from CtxScraplingBlock.

Field Type Default
url str required
title str ''
content str required
content_type str 'text'
char_count int required
degraded bool False
degradation_reason str \| None None
completion_state Literal['verified', 'qualified-draft', 'blocked-escalated'] 'qualified-draft'
warning_card dict[str, Any] Field(default_factory=dict)
evidence dict[str, Any] Field(default_factory=dict)
request_id str ''
task_id str ''
run_id str ''
backend_attempted str ''
backend_used str ''

CtxScraplingBlock(AIBlock[ScrapeInput, ScrapeOutput, None])

Resilient web scraping block.

Field Type Default
name str 'ctx_scrapling'
resource_bounds ResourceBounds \| None None
usage ResourceUsage field(default_factory=ResourceUsage)

Methods:

infer(data: ScrapeInput) -> Result[ScrapeOutput]

MCPScraplingRecord(BaseModel)

Field Type Default
id str required
record_type str required
key str required
value str required
tags list[str] Field(default_factory=list)
timestamp str required
metadata dict[str, Any] Field(default_factory=dict)

MCPScraplingInput(BaseModel)

Field Type Default
op Literal['fetch_static', 'fetch_dynamic', 'fetch_stealth', 'fetch_post', 'fetch_multi', 'parse_css', 'parse_xpath', 'parse_text_search', 'parse_regex', 'parse_table', 'crawl_start', 'crawl_page', 'crawl_status', 'crawl_results', 'crawl_stop', 'store_page', 'retrieve_page', 'query_pages', 'store_selector', 'search_store', 'extract_links', 'extract_metadata', 'auto_selector', 'smart_extract', 'scrapling_info'] required
url str ''
urls list[str] Field(default_factory=list)
headers dict[str, str] Field(default_factory=dict)
body str ''
timeout float 30.0
fetcher_type str 'static'
html str ''
selector str ''
pattern str ''
text_query str ''
session_id str ''
allowed_domains list[str] Field(default_factory=list)
max_depth int 3
max_pages int 100
start_url str ''
page_id str ''
title str ''
content str ''
content_type str ''
status_code int 200
domain str ''
tags list[str] Field(default_factory=list)
metadata_json str '{}'
selector_name str ''
selector_type str 'css'
selector_value str ''
description str ''
query str ''
limit int 50
top_k int 5
offset int 0
fields list[str] Field(default_factory=list)
domain_filter str ''
extraction_prompt str ''
agentic_rerank bool \| None None
run_mode Literal['beta', 'production'] 'beta'
reviewer_signature str ''

MCPScraplingOutput(BaseModel)

Field Type Default
op str required
key str ''
value str ''
found bool False
count int 0
records list[MCPScraplingRecord] Field(default_factory=list)
content str ''
title str ''
url str ''
status_code int 0
links list[str] Field(default_factory=list)
items list[dict[str, Any]] Field(default_factory=list)
selector_generated str ''
summary str ''
message str ''
metadata dict[str, Any] Field(default_factory=dict)
degraded bool False
degradation_reason str ''
completion_state Literal['verified', 'qualified-draft', 'blocked-escalated'] 'qualified-draft'
warning_card dict[str, Any] Field(default_factory=dict)
evidence dict[str, Any] Field(default_factory=dict)
request_id str ''
task_id str ''
run_id str ''
agentic_evidence dict[str, Any] Field(default_factory=dict)

CtxScraplingMCPBlock(AIBlock[MCPScraplingInput, MCPScraplingOutput, dict])

Full-featured web scraping block with SQLite persistence.

Field Type Default
name str 'ctx_scrapling_mcp'
state dict \| None None
db_path str ':memory:'
resource_bounds ResourceBounds \| None None
usage ResourceUsage field(default_factory=ResourceUsage)
agentic_planner CtxScraplingPlanner \| None None

Methods:

infer(data: MCPScraplingInput) -> Result[MCPScraplingOutput]

ScraplingStore

Sync SQLite scrapling store with 8 tables.

Constructor:

Parameter Type Default
db_path str ':memory:'

Methods:

add_page(url: str, domain: str, title: str, html: str, content: str, content_type: str, status_code: int, fetcher_type: str, tags: list[str], metadata_json: str = '{}') -> str

get_page(url: str = '', page_id: str = '') -> dict[str, Any] | None

query_pages(domain: str = '', tags: list[str] | None = None, query: str = '', limit: int = 50) -> list[dict[str, Any]]

add_item(page_id: str, url: str, selector: str, data: dict, extraction_method: str, tags: list[str]) -> str

query_items(page_id: str = '', limit: int = 50) -> list[dict[str, Any]]

upsert_selector(name: str, selector_type: str, selector_value: str, description: str, domain: str, tags: list[str]) -> str

get_selector(name: str) -> dict[str, Any] | None

query_selectors(domain: str = '', limit: int = 50) -> list[dict[str, Any]]

create_session(start_url: str, allowed_domains: list[str], max_depth: int, max_pages: int, fetcher_type: str, config_json: str = '{}') -> str

get_session(session_id: str) -> dict[str, Any] | None

pop_queue(session_id: str) -> dict[str, Any] | None

complete_queue_item(queue_id: str) -> None

add_to_queue(session_id: str, url: str, depth: int, parent_url: str) -> str

increment_session_pages(session_id: str) -> None

increment_session_items(session_id: str, count: int = 1) -> None

stop_session(session_id: str) -> None

get_queue_stats(session_id: str) -> dict[str, int]

add_crawl_item(session_id: str, url: str, data: dict) -> str

query_crawl_items(session_id: str, limit: int = 50, offset: int = 0) -> list[dict[str, Any]]

add_link(source_url: str, target_url: str, anchor_text: str, domain: str, session_id: str = '') -> str

query_links(source_url: str = '', domain: str = '', limit: int = 50) -> list[dict[str, Any]]

upsert_extraction_rule(name: str, description: str, url_pattern: str, selector_value: str, selector_type: str, output_fields: list[str], domain: str, tags: list[str]) -> str

text_search(query: str, top_k: int = 5) -> list[dict[str, Any]]

TF-IDF search across pages and selectors.

count_all() -> dict[str, int]

Functions

eligible_fingerprint(records: list[Any]) -> str

sha256 over the returned record texts (order-sensitive).

validate_scrapling_rerank_decision(decision: ScraplingRerankDecision, n_eligible: int, expected_fingerprint: str) -> None

Returned-set / anti-injection guard for a search-rerank decision.

planner_is_llm_trusted(planner: Any) -> bool

Whether the BLOCK may report llm_used=True for planner.

MCP Tools

Operation Source
fetch_static scrapling_mcp
fetch_dynamic scrapling_mcp
fetch_stealth scrapling_mcp
fetch_post scrapling_mcp
fetch_multi scrapling_mcp
parse_css scrapling_mcp
parse_xpath scrapling_mcp
parse_text_search scrapling_mcp
parse_regex scrapling_mcp
parse_table scrapling_mcp
crawl_start scrapling_mcp
crawl_page scrapling_mcp
crawl_status scrapling_mcp
crawl_results scrapling_mcp
crawl_stop scrapling_mcp
store_page scrapling_mcp
retrieve_page scrapling_mcp
query_pages scrapling_mcp
store_selector scrapling_mcp
search_store scrapling_mcp
extract_links scrapling_mcp
extract_metadata scrapling_mcp
auto_selector scrapling_mcp
smart_extract scrapling_mcp
scrapling_info scrapling_mcp