detect_site
Report what platform a site runs on and which strategy to use. Cheap; call it before a large job.
url必填
io.github.Ozymandias-Owens-2由 GitHub 帳號 Ozymandias-Owens-2 發布v1.0.3更新於 Oct 24, 2026
Give it a URL, get structured rows. A model writes the parser once; replays are free.
讓助理把電商型錄與自訂頁面擷取成結構化資料,每個網站只需編譯一次解析器,之後免費重播。
Web executable,透過 Streamable HTTP。 遠端服務在工作區中設定後即可從網頁執行環境執行。
把這段提示詞貼上到 Claude Code、Codex、Cursor 等代理程式,或 SourceWeft 對話中。代理程式會讀取該伺服器的安裝指南,先向你展示發布者、端點和登入方式,經你同意後再把它新增到你的客戶端。金鑰不會寫進任何命令。
閱讀 https://sourceweft.com/mcp/io.github.Ozymandias-Owens-2%2Fscrapewright/install.md,並按其中說明把這個 MCP 伺服器接入我的客戶端。修改任何設定之前,先告訴我它的發布者、端點和登入方式,等我確認。不要把 API 金鑰寫進命令或我會提交的檔案;問我金鑰應從哪裡取得。把它新增到你客戶端的 mcpServers 設定中。
{
"mcpServers": {
"scrapewright": {
"type": "http",
"url": "https://scrapewright.app/mcp",
"headers": {
"X-API-Key": "<YOUR_API_KEY>"
}
}
}
}[PyPI] [Python] [License: MIT]
Give it a URL. It writes the scraper.
Most e-commerce catalog scraping splits into two worlds: sites on a known platform (Shopify, WooCommerce) that expose a clean JSON feed, and everything else — bespoke HTML where you hand-write a parser per site and re-write it every time the markup shifts. scrapewright collapses both into one call:
The LLM is a compiler, not a runtime. It runs once per site to produce a recipe of CSS selectors; every page after that is parsed by plain BeautifulSoup at zero marginal cost. That is the whole cost-control story — no per-page model calls, no token bill that scales with your crawl.
Everything normalizes to one Product shape, so downstream code never knows or
cares which path a record came from.
-o writes .csv (Excel-ready, UTF-8 BOM), .xlsx (pip install scrapewright[excel]),
or .jsonl; without it, products stream to stdout as JSONL.
detect answers the routing question before a job starts:
Twelve platforms are recognized: Shopify and WooCommerce publish a free
JSON catalog, so those route to catalog — deterministic, no LLM, no browser.
Magento, BigCommerce, Salesforce Commerce Cloud, Squarespace, Wix, Webflow,
PrestaShop, Shopware, Ecwid and OpenCart are recognized by fingerprint and
route to crawl, where the recipe path handles them like any custom site — the
point of naming them is knowing what you face, not writing twelve parsers.
Wix and Ecwid render client-side, so detection says crawl+js up front.
A site behind an anti-bot wall reports strategy: blocked with the HTTP status,
rather than pretending it found nothing.
Products are just the built-in default. Declare the fields you want and the same compile-once/replay-free loop works on any structured page — job posts, listings, registry records:
Field kinds are text (default), number, url, and list. A number field is
parsed out of whatever the page wrote — "£51.77", "1.250,00", "€72,000" all
become numbers — and when the page said more than the digits, the original is kept
next to it as <field>_text:
A value that holds no number at all ("call us") is left as the page wrote it rather than dropped. Recipes are cached per site and per schema, so one domain can be compiled against several field sets without them overwriting each other.
scrapewright speaks MCP, so an agent can call it as a tool instead of reading raw HTML itself. Two ways in.
Hosted, nothing to install. Point the client at the service with a key from scrapewright.app (1,000 free rows a month; an account that has never been topped up compiles one new site and renders twenty pages a day):
Tools: detect_site, extract_page, crawl_site, crawl_status, account. Paid
from the same credit balance as the REST API; no model key of your own is needed.
Local, your own model key. Run the server on your machine:
Point any MCP client at that command and the agent gains five tools: detect_site,
scrape_catalog, extract_page, crawl_site, and list_learned_sites.
Drop this into your client's config — Claude Desktop, Cursor, or anything else that speaks MCP:
The key is only needed for sites on no known platform, where a recipe has to be written once. Shopify and WooCommerce stores work without it.
The economics are the point. An agent that reads pages itself pays model tokens per page, forever. These tools pay once per site — an agent crawling 500 pages spends one synthesis, not five hundred, and platform stores (Shopify, WooCommerce) cost nothing at all.
The same core behind an HTTP API, with keys, quotas, metering and background jobs:
Or skip the API: scrapewright.app/account takes a listing URL and a field list, runs the crawl, and hands back the spreadsheet.
One action costs real money: compiling a new site, a single LLM pass over a page, measured at $0.02 on a small product page and $0.15 on a heavy rendered one. Everything after that is BeautifulSoup — the ten-thousandth record from a compiled site is free to serve. So credits are priced off that one action, and everything else is denominated relative to it:
Margin is measured on compiling a site, because that is the only step that costs anything; a test fails if a price edit drops any pack below 60%. A free account can cost us at most $0.20 a month, even if every free credit goes to the most expensive action there is.
Credits are a ledger, not a counter — every grant and every charge is a row,
so a disputed bill can be reconstructed line by line, and a replayed payment
webhook cannot double-credit (grants take an idempotency key). Running out
returns 402 with the balance and what to do about it; a crawl is capped by the
credits on hand, so a job stops at what the caller can pay for instead of
overdrawing.
Stripe is wired in and turned on by environment, not by a code change:
The webhook endpoint takes no API key — Stripe is the caller, so the signature is the credential, and an unverified endpoint would be a free credit printer for anyone who guessed the URL. Three rules hold the integration up:
examples/stripe_smoke_test.py runs the whole path against Stripe's test mode
with the 4242 card. Any other provider plugs into the same two-method
BillingProvider protocol in scrapewright.service.billing; without one, the
service simply runs free, which is the right default for a demo or a self-hosted
instance.
Docker:
Add --js (or Scrapewright(js=True)) and pages that render their catalog in the
browser become extractable:
Rendering stays rare by construction: the static fetch runs first, and Chromium is
only started when the static HTML is an empty client-side shell or extraction on it
fails. A recipe learned from rendered HTML is tagged needs_js, so later runs on that
site skip the wasted static hop. The browser starts at most once per run and is reused
for every page.
Product shapeA record is usable when it carries a title, a price, and a URL. The
validator (scrapewright.coverage) reports the usable ratio across a batch —
the number a recipe is trusted on before it's cached.
max_synth_per_run (default 3) — a site that resists synthesis cannot burn
one model call per page. The bill is bounded no matter how large the crawl.model and works with any
injected client; the default targets Anthropic's Claude via the official SDK.The deterministic paths are fully covered by offline fixtures — no network, no model calls — so CI is green without an API key:
v0.9 (alpha). Implemented and tested: an HTTP service with API keys, prepaid credits (priced off the one action that costs money, on an auditable ledger) and Stripe checkout with a signature-verified webhook, cost metering and background jobs; platform detection across 12 storefronts with a recommended strategy per site, catalog extraction (Shopify, WooCommerce), page extraction (JSON-LD, LLM-synthesized selectors), recipe caching, self-healing re-synthesis with a bounded per-run model budget, a crawl frontier (one listing URL → the whole site), JS rendering via an optional Playwright fetcher with automatic escalation, schema-agnostic extraction (bring your own fields), an MCP server for AI agents, coverage validation, and CSV / XLSX / JSONL export. 141 offline tests.
Known limit, stated plainly: it does not defeat anti-bot walls — deliberately out of scope. Sites behind Akamai/Fastly-style challenges return an honest miss.
Roadmap: pagination strategies for infinite-scroll listings, and a deployed instance of the service.
MIT — see LICENSE.
來源:README.md,提交 9c05167
Report what platform a site runs on and which strategy to use. Cheap; call it before a large job.
url必填Extract structured data from ONE page. ``fields`` declares your own schema, e.g. ["title", "salary:number", "tags:list"]; omit it for the product schema. First call on a new site compiles a recipe (300 credits); later calls replay it for 1 credit per row. A site nobody could read is remembered for a week and answered without calling the model, so re-reading a dead page costs nothing. `retry` asks anyway.
jsurl必填retryfieldsWalk a site and extract every item. Waits up to four minutes; a longer crawl returns a job_id to pass to crawl_status. `mode` picks how the items are found. "rows" (the default) reads every card on the listing itself and follows its pagination -- right for search results, categories and tables. "links" follows each card into its own page, for sites where an item has one. "like" starts from one example item page, given as `like_page`, and finds every other page shaped like it; pass `listing_url` as well when you know the stock or results page, because inferring it is the part that fails.
jsmodefieldsscrolllike_pagemax_itemslisting_url必填Fetch a crawl that outlived its call.
job_id必填Credits left and this month's usage for the key in use.
無需輸入參數。
已滿足適用檢查項的 100%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
┌─────────────┐ store URL ───▶ │ detect │ └──────┬──────┘ ┌──────────────────┼──────────────────┐ ▼ ▼ ▼ shopify woocommerce generic HTML products.json wc/store/products (page mode) │ │ │ │ deterministic │ ▼ │ (free) │ cached recipe? ──yes──▶ replay (free) └────────┬─────────┘ │ no ▼ ▼ Product{} ◀───── selectors ── JSON-LD? ──yes──▶ Product{} (free) ▲ │ no │ ▼ └──────── replay ◀── LLM synthesizes recipe ONCE ──▶ cachepip install scrapewright # deterministic paths (Shopify, Woo, JSON-LD)pip install "scrapewright[llm]" # + LLM recipe synthesis for custom HTMLpip install "scrapewright[llm,js,excel,mcp]" # + JS rendering, XLSX, MCP serverplaywright install chromium # only needed for --jsfrom scrapewright import Scrapewright
sw = Scrapewright()
# Catalog mode — a whole Shopify/WooCommerce store, deterministicallyfor product in sw.scrape_catalog("https://shop.example.com", max_items=200): print(product.brand, product.title, product.price, product.currency)
# Page mode — one custom-HTML product page.# First call: tries JSON-LD (free); if absent, the LLM writes a recipe once.# Every later call on that domain: replayed from the cached recipe, no LLM.item = sw.scrape_page("https://boutique.example.com/products/wool-coat")print(item.model_dump(exclude={"raw"}))
# Crawl mode — walk a WHOLE custom store from one listing/category URL.# The frontier discovers product pages (deterministic, free); the first page# pays the single synthesis cost, every other page replays the recipe.for product in sw.crawl("https://boutique.example.com/collection", max_items=100): print(product.title, product.price)scrapewright detect https://shop.example.com # platform + strategyscrapewright run https://shop.example.com --max 50 # scrape a catalog → JSONLscrapewright crawl https://boutique.example.com/collection -o products.xlsxscrapewright run https://shop.example.com -o products.csv # Excel-ready CSVscrapewright add https://boutique.example.com/products/coat # learn a sitescrapewright run https://boutique.example.com/products/coat --no-llmscrapewright list # cached recipe domains$ scrapewright detect https://some-store.comhttps://some-store.com platform: bigcommerce catalog: - strategy: crawl note: BigCommerce (Stencil) markupscrapewright run https://jobs.example.com/p/123 -f title -f company -f salary:number -f tags:list --schema-name jobfrom scrapewright import Scrapewright, Schema
job = Schema.from_names(["title", "company", "salary:number", "tags:list"], name="job")record = Scrapewright().extract("https://jobs.example.com/p/123", job)print(record.data) # {'title': ..., 'company': ..., 'salary': ..., 'tags': [...]}{ "price": 51.77, "price_text": "£51.77" }{ "mcpServers": { "scrapewright": { "url": "https://scrapewright.app/mcp", "headers": { "X-API-Key": "sw_..." } } }}pip install "scrapewright[mcp,llm]"scrapewright mcp{ "mcpServers": { "scrapewright": { "command": "uvx", "args": ["--from", "scrapewright[mcp,llm]", "scrapewright", "mcp"], "env": { "ANTHROPIC_API_KEY": "sk-ant-..." } } }}pip install "scrapewright[service,llm]"scrapewright keys create --label alice --plan freescrapewright serve --port 8000curl -X POST localhost:8000/v1/extract -H "X-API-Key: sw_..." -H "Content-Type: application/json" -d '{"url": "https://shop.example.com/products/coat"}'$ scrapewright planspack credits price $/credit marginstarter 10,000 $10 0.00100 80.0%growth 50,000 $40 0.00080 75.0%scale 250,000 $150 0.00060 66.7%
Free: 1,000 credits a month, resetting.scrapewright credits grant <key_id> --pack starter --idempotency <payment_id>scrapewright credits balance <key_id>pip install "scrapewright[service,stripe]"export STRIPE_SECRET_KEY=sk_test_... # absent -> nothing is for saleexport STRIPE_WEBHOOK_SECRET=whsec_... # absent -> webhooks are refusedscrapewright servedocker build -t scrapewright . # static pathsdocker build -t scrapewright --build-arg WITH_JS=1 . # + headless Chromiumdocker run -p 8000:8000 -v sw-data:/data scrapewrightscrapewright run https://spa-store.example.com/products/x --page --jsscrapewright crawl https://spa-store.example.com/shop --js -o products.xlsxurl: str # canonical product URLtitle: strbrand: str | Noneprice: Decimal | None # parsed from "1,250.00" / "1.250,00" / "€1290" alikecurrency: str | Noneavailable: bool | Noneimages: list[str] # absolute URLssizes: list[str]description: str | Nonesku: str | Nonesource_platform: str # shopify | woocommerce | json-ld | selectorpip install "scrapewright[dev]"pytest