Help us shape the future of Go! Take the 2026 Go Developer Survey

ScrapeGoat

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 3, 2026 License: Apache-2.0

README

ScrapeGoat

The high-performance web scraping framework written in Go.

Scrapy's architecture + Go's concurrency + MCP integration + LLM extraction. One binary, no required services.

Go Report Card Go Reference MCP Compatible


Why ScrapeGoat in 2025?

Tool Weakness ScrapeGoat's Advantage
Scrapy Python, slower concurrency, no MCP Go goroutines, single-binary deploy, native MCP server
Playwright Heavy browser automation, no extraction Lightweight HTTP + LLM-powered structured extraction
Apify SaaS lock-in, paid tiers Self-hosted, open-source, REST API included
Colly Limited pipeline, no anti-bot Full middleware pipeline + adaptive anti-bot engine
FireCrawl SaaS only, API limits Self-hosted, unlimited, same LLM extraction

ScrapeGoat combines Scrapy's architecture with Go's concurrency, MCP tool integration, and LLM-powered extraction — all in a single binary.


Quick Start

# Install
go install github.com/IshaanNene/ScrapeGoat/cmd/scrapegoat@latest

# Auto-extract structured data from any URL (no code needed!)
scrapegoat extract https://books.toscrape.com

# Create a project
scrapegoat new project my_scraper
cd my_scraper

# Run your spider
go run ./spiders/

One-Liner Auto-Extract

$ scrapegoat extract https://books.toscrape.com

{
  "url": "https://books.toscrape.com",
  "title": "All products | Books to Scrape",
  "type": "product",
  "data": [
    {"_type": "product", "name": "A Light in the Attic", "price": "£51.77", "rating": 3},
    {"_type": "product", "name": "Tipping the Velvet", "price": "£53.74", "rating": 1}
  ]
}

Architecture

graph TD
    CLI["CLI / SDK"] --> CFG["Config"]
    CFG --> ENG["Engine"]
    ENG --> SCH["Scheduler"]
    ENG --> FRT["Frontier<br>(Priority Queue)"]
    ENG --> DDP["Deduplicator<br>(Exact set or Bloom)"]
    ENG --> RBT["Robots Manager"]
    ENG --> CHK["Checkpoint Manager"]
    ENG --> MET["Prometheus Metrics"]
    SCH --> WRK["Worker Pool<br>(Fixed size)"]
    WRK -->|"dequeue"| FRT
    WRK -->|"request middleware"| MID["Request Pipeline<br>(7 middlewares)"]
    MID --> FET["Fetcher<br>(HTTP / Browser)"]
    FET --> PXY["Proxy Manager"]
    FET -->|"response"| PAR["Parser<br>(CSS / XPath / Regex)"]
    PAR -->|"items"| PIP["Item Pipeline<br>(12 middlewares)"]
    PAR -->|"new URLs"| FRT
    PIP --> STR["Storage<br>(JSON / JSONL / CSV)"]
    PIP -. "experimental plugin stubs" .-> PLG["S3 / Kafka / Postgres"]

    style CLI fill:#4A90D9,color:#fff
    style ENG fill:#E67E22,color:#fff
    style SCH fill:#E67E22,color:#fff
    style WRK fill:#E67E22,color:#fff
    style FRT fill:#2ECC71,color:#fff
    style DDP fill:#2ECC71,color:#fff
    style MID fill:#9B59B6,color:#fff
    style FET fill:#9B59B6,color:#fff
    style PAR fill:#1ABC9C,color:#fff
    style PIP fill:#E74C3C,color:#fff
    style STR fill:#3498DB,color:#fff
    style PLG fill:#7F8C8D,color:#fff

Spider Interface (Scrapy-Style)

type ProductSpider struct{}

func (s *ProductSpider) Name() string { return "products" }

func (s *ProductSpider) StartURLs() []string {
    return []string{"https://books.toscrape.com"}
}

func (s *ProductSpider) Parse(resp *scrapegoat.Response) (*scrapegoat.SpiderResult, error) {
    result := &scrapegoat.SpiderResult{}
    resp.Doc.Find(".product_pod").Each(func(i int, s *goquery.Selection) {
        item := scrapegoat.NewItem(resp.URL)
        item.Set("title", s.Find("h3 a").AttrOr("title", ""))
        item.Set("price", s.Find(".price_color").Text())
        result.Items = append(result.Items, item)
    })
    return result, nil
}

func main() {
    scrapegoat.RunSpider(&ProductSpider{},
        scrapegoat.WithConcurrency(10),
        scrapegoat.WithMaxDepth(3),
        scrapegoat.WithOutput("json", "./output"),
    )
}

Features

Category Features
Core Engine Priority queue frontier, per-domain throttling, fixed-size worker pool, exact or Bloom dedup, per-domain rate limiting, circuit breaker
MCP Server JSON-RPC 2.0, stdio + HTTP/SSE transports, 8 tools for Claude/Cursor/Cline
LLM Extraction OpenAI, Anthropic, Ollama backends; schema-based extraction; SQLite caching
API Server REST + WebSocket, job management, real-time streaming, API key auth, CORS
Anti-Bot uTLS browser fingerprints (JA3 matched to the advertised User-Agent), pattern-based block detection, adaptive strategy escalation
Parsing CSS selectors, XPath, Regex, JSON-LD, OpenGraph, structured data, auto-extraction
Transforms Schema validation (7 types), 6 composable transforms, drop/annotate/log failure modes
Change Detection SQLite-persisted monitoring, hash/selector diffing, webhook notifications
SDKs Python (sync + async, httpx + pydantic) and TypeScript (native fetch, zero deps)
Crawl Graph SQLite-backed URL graph, DOT/Mermaid/JSON/CSV export, replay strategies
Plugin SDK init() registration, BasePlugin embeddable, filter/transform middleware helpers
Middleware 7 request middlewares + 12 item pipeline middlewares, fully extensible
Storage JSON, JSONL, CSV file storage; experimental S3/Kafka/PostgreSQL plugin stubs
Distributed Master/worker HTTP coordination; Redis-backed task queue with at-least-once delivery and abandoned-task recovery, or in-memory for single-process
Browser Headless Chromium via go-rod, JS rendering, form filling, infinite scroll
Observability Prometheus metrics endpoint, web dashboard, real-time stats
DevEx CLI scaffolding, REPL, YAML config, checkpoint pause/resume (--resume), robots.txt compliance

Subsystems that are implemented and tested but not yet wired into the crawl path — the autoscaled pool and in-process tracing — are tracked in ROADMAP.md rather than listed above. If it is in the table, it runs.


Security posture

A crawler is a program that fetches URLs someone else chose. When it also exposes an MCP server, those URLs come from a model whose output was shaped by the last page it read — which is a prompt-injection channel aimed straight at your network.

ScrapeGoat treats that as the threat model rather than an edge case:

  • Outbound requests are guarded. Scheme allowlist, plus post-DNS blocking of loopback, RFC1918, link-local (including the cloud metadata endpoint at 169.254.169.254), CGNAT, and their IPv4-mapped and NAT64-embedded equivalents.
  • DNS rebinding does not work. The guard resolves once and dials the address it validated, rather than handing the hostname back to the resolver.
  • Every redirect hop is re-checked. A 302 to the metadata endpoint is blocked at hop three the same as at hop one.
  • The API server fails closed. No API key, no start — unless you pass --insecure-no-auth. CORS is deny-by-default and WebSocket upgrades check Origin.
  • Responses are capped after decompression, with a compression-ratio limit, so a gzip bomb cannot exhaust memory.

Separately, fetcher.fingerprint: chrome|firefox|safari|edge|random makes the TLS ClientHello a real browser's via uTLS, with the User-Agent and headers bound to it — a Chrome JA3 arriving with a Firefox User-Agent is a stronger automation signal than an honest Go fingerprint. Verified against captured ClientHello bytes rather than asserted; see internal/fetcher/fingerprint. It closes the loudest signal ("this is a Go program") and nothing more — HTTP/2 SETTINGS, header order, TCP characteristics, and behaviour are all still tells.

Opt out for internal crawling with safety.allow_private_addresses. The full trust boundary, including what is not covered — proxied requests and the headless browser — is in SECURITY.md.


CLI Commands

scrapegoat crawl <url>           # Crawl with link following
scrapegoat extract <url>         # Auto-extract structured data
scrapegoat search <url>          # Full-text search indexing
scrapegoat serve                 # Start REST/WebSocket API server
scrapegoat mcp                   # Start MCP server (stdio or HTTP)
scrapegoat graph                 # Export crawl graph (json/dot/mermaid/csv)
scrapegoat replay                # Generate re-crawl URL list from graph
scrapegoat watch <urls...>       # Monitor URLs for content changes
scrapegoat diff <url>            # Show change history for a URL
scrapegoat new spider <name>     # Scaffold a spider
scrapegoat new project <name>    # Scaffold entire project
scrapegoat master                # Start distributed coordinator
scrapegoat worker                # Start distributed worker
scrapegoat scale <n>             # Scale workers
scrapegoat dashboard             # Launch web dashboard
scrapegoat benchmark <url>       # Performance benchmarks
scrapegoat config                # Show configuration
scrapegoat version               # Print version

Plugin Ecosystem

// Register built-in plugins
registry := plugin.NewRegistry(logger)
builtin.RegisterBuiltinPlugins(registry, logger)

// Experimental built-in plugin stubs:
// • scrapegoat-s3        — writes S3-shaped batches to a local fallback
// • scrapegoat-kafka     — logs publish operations for future Kafka integration
// • scrapegoat-postgres  — buffers/logs inserts for future PostgreSQL integration

// Custom plugin
type MyPlugin struct{}
func (p *MyPlugin) Name() string            { return "my-plugin" }
func (p *MyPlugin) Type() plugin.PluginType { return plugin.PluginTypeStorage }
func (p *MyPlugin) Store(items []*types.Item) error { /* ... */ }

Distributed Crawling

# Terminal 1: Start master
scrapegoat master --addr :8081

# Terminal 2-4: Start workers
scrapegoat worker --master http://localhost:8081 --capacity 10

# Submit crawl task
curl -X POST http://localhost:8081/api/submit \
  -d '{"type":"crawl","urls":["https://example.com"]}'

Configuration

engine:
  concurrency: 10
  max_depth: 5
  politeness_delay: 1s
  respect_robots_txt: true

browser:
  render: false
  browser_type: chromium
  headless: true

middleware:
  request:
    - name: header_rotation
    - name: request_fingerprint
    - name: captcha_detection
    - name: cloudflare_detection

storage:
  type: json
  output_path: ./output

distributed:
  enabled: false
  master_addr: ":8081"
  # Redis fields are placeholders until the real Redis queue backend lands.
  redis_addr: "localhost:6379"

Docker

docker-compose up -d
scrapegoat crawl https://example.com

Project Structure

ScrapeGoat/
├── cmd/scrapegoat/          # CLI entry point (20 commands)
├── pkg/scrapegoat/          # Public SDK (Spider + Crawler APIs)
├── internal/
│   ├── engine/              # Core: scheduler, frontier, dedup, bloom, autoscale, checkpoint, robots
│   ├── mcp/                 # MCP server (JSON-RPC 2.0, stdio+HTTP transport, 8 tools)
│   ├── llmextract/          # LLM extraction engine (OpenAI, Anthropic, Ollama + SQLite cache)
│   ├── apiserver/           # REST + WebSocket API server with job management
│   ├── antibot/             # Adaptive anti-bot engine, stealth profiles, human simulation
│   ├── crawlgraph/          # Crawl graph with SQLite, export (DOT/Mermaid/JSON/CSV), replay
│   ├── changedetect/        # Content change monitoring with notifications
│   ├── transforms/          # Schema validation + composable data transforms
│   ├── middleware/           # Request middleware pipeline (7 built-in)
│   ├── fetcher/             # HTTP/browser fetcher, proxy, stealth, CAPTCHA, session pool
│   ├── parser/              # CSS, XPath, regex, structured data, auto-extractor
│   ├── pipeline/            # Item processing pipeline (12 middlewares)
│   ├── storage/             # JSON, JSONL, CSV storage
│   ├── plugin/              # Plugin registry + SDK + experimental storage stubs
│   ├── distributed/         # Master/worker, in-memory task queue
│   ├── observability/       # Prometheus metrics, in-process tracing primitives
│   ├── dashboard/           # Web dashboard
│   ├── automation/          # Browser automation (go-rod)
│   ├── benchmark/           # Performance comparison tool
│   ├── seo/                 # SEO audit, sitemap crawler
│   ├── repl/                # Interactive REPL
│   └── config/              # Configuration management + validation
├── sdks/
│   ├── python/              # Python SDK (httpx + pydantic, sync + async)
│   └── typescript/          # TypeScript SDK (native fetch, zero deps)
├── examples/                # 9 example spiders
├── docs/                    # Architecture, API spec (OpenAPI), MCP setup, quickstart
├── configs/                 # Default YAML configs
└── .github/workflows/       # CI: tests, benchmarks, Python SDK

Testing

make test           # Unit tests
make test-race      # Race condition detection
make bench          # Benchmarks
make lint           # Linting
make build          # Build binary
Golden-file parser tests

internal/parser/testdata/ holds a corpus of pages built around specific hazards — unclosed tags, attribute soup, broken JSON-LD, <base href>, dangerous URL schemes, entity edge cases — with golden files pinning the parser's output for each. It has already caught one real bug (<base href> being ignored during link resolution).

go test ./internal/parser -run TestGolden           # check
go test ./internal/parser -run TestGolden -update   # rebaseline, then read the diff
Fuzzing

Everything ScrapeGoat parses comes from a site it does not control, so the parsers are fuzz-tested and CI runs each target for 60 seconds on every push. Targets cover HTML parsing, CSS selectors, regex patterns, URL canonicalisation, robots.txt parsing and pattern matching, the decompression path, Retry-After, the MCP JSON-RPC decoder, and the SSRF guard.

go test -run=XXX -fuzz=FuzzCompositeParse -fuzztime=60s ./internal/parser

Documentation


Contributing

See CONTRIBUTING.md for guidelines.

License

Apache License 2.0 — see LICENSE for details.


Built in Go

Star on GitHub · Docs · Issues

Directories

Path Synopsis
cmd
scrapegoat command
examples
aicrawl command
AI Web Crawler — crawls sites and uses LLM to summarize, extract entities, and analyze sentiment Requires Ollama running locally: ollama serve && ollama pull llama3.2
AI Web Crawler — crawls sites and uses LLM to summarize, extract entities, and analyze sentiment Requires Ollama running locally: ollama serve && ollama pull llama3.2
ecommerce command
E-Commerce Product Scraper — scrapes books.toscrape.com Extracts: title, price, rating, availability, description, image
E-Commerce Product Scraper — scrapes books.toscrape.com Extracts: title, price, rating, availability, description, image
github command
GitHub Trending Scraper — scrapes today's trending repos Extracts: repo name, description, language, stars, forks, stars gained today
GitHub Trending Scraper — scrapes today's trending repos Extracts: repo name, description, language, stars, forks, stars gained today
hackernews command
Hacker News Scraper — scrapes front page stories Extracts: rank, title, URL, points, author
Hacker News Scraper — scrapes front page stories Extracts: rank, title, URL, points, author
news command
Multi-Site News Aggregator — crawls multiple news sources Extracts structured data (JSON-LD, OpenGraph, meta) from any news site
Multi-Site News Aggregator — crawls multiple news sources Extracts structured data (JSON-LD, OpenGraph, meta) from any news site
product_scraper command
Product Scraper Example
Product Scraper Example
search command
Search Engine Crawler — indexes pages with full text, metadata, and link graph Produces a search-engine-style index: title, URL, body text, meta, headings, links
Search Engine Crawler — indexes pages with full text, metadata, and link graph Produces a search-engine-style index: title, URL, body text, meta, headings, links
spider command
Example: Using the Spider interface for structured, Scrapy-style crawling.
Example: Using the Spider interface for structured, Scrapy-style crawling.
wikipedia command
Wikipedia Knowledge Extractor — deep crawl with 1000 article limit Extracts: title, summary, categories, reference count, external links
Wikipedia Knowledge Extractor — deep crawl with 1000 article limit Extracts: title, summary, categories, reference count, external links
internal
ai
antibot
Package antibot implements an adaptive anti-bot engine with block detection, stealth profiles, and human behaviour simulation.
Package antibot implements an adaptive anti-bot engine with block detection, stealth profiles, and human behaviour simulation.
api
apiserver
Package apiserver implements a REST and WebSocket API server for ScrapeGoat, enabling microservice deployment and programmatic access to crawling, extraction, and job management.
Package apiserver implements a REST and WebSocket API server for ScrapeGoat, enabling microservice deployment and programmatic access to crawling, extraction, and job management.
changedetect
Package changedetect implements a content monitoring engine that detects changes on web pages using multiple diffing strategies and notifications.
Package changedetect implements a content monitoring engine that detects changes on web pages using multiple diffing strategies and notifications.
crawlgraph
Package crawlgraph implements a directed graph of URLs discovered during crawling, with support for SQLite persistence, multiple export formats, and replay strategies for re-crawling changed or failed pages.
Package crawlgraph implements a directed graph of URLs discovered during crawling, with support for SQLite persistence, multiple export formats, and replay strategies for re-crawling changed or failed pages.
fetcher/fingerprint
Package fingerprint makes ScrapeGoat's TLS handshake and HTTP headers look like the browser it claims to be.
Package fingerprint makes ScrapeGoat's TLS handshake and HTTP headers look like the browser it claims to be.
llmextract
Package llmextract provides a schema-driven LLM extraction pipeline that uses large language models to extract structured data from HTML content.
Package llmextract provides a schema-driven LLM extraction pipeline that uses large language models to extract structured data from HTML content.
mcp
Package mcp implements a Model Context Protocol (MCP) server that exposes ScrapeGoat's crawling, extraction, and SEO tools to AI agents such as Claude, GPT-4, Cursor, and Cline via JSON-RPC 2.0 over stdio or HTTP/SSE.
Package mcp implements a Model Context Protocol (MCP) server that exposes ScrapeGoat's crawling, extraction, and SEO tools to AI agents such as Claude, GPT-4, Cursor, and Cline via JSON-RPC 2.0 over stdio or HTTP/SSE.
observability
Package observability exposes ScrapeGoat's operational metrics.
Package observability exposes ScrapeGoat's operational metrics.
plugin/sdk
Package plugin/sdk provides helper types and functions for building ScrapeGoat plugins using the init() registration pattern.
Package plugin/sdk provides helper types and functions for building ScrapeGoat plugins using the init() registration pattern.
safety
Package safety enforces the network trust boundary for every outbound fetch.
Package safety enforces the network trust boundary for every outbound fetch.
seo
testutil
Package testutil holds helpers shared across ScrapeGoat's test packages.
Package testutil holds helpers shared across ScrapeGoat's test packages.
transforms
Package transforms extends the pipeline with schema validation, data transformation, and enrichment middlewares.
Package transforms extends the pipeline with schema validation, data transformation, and enrichment middlewares.
pkg
scrapegoat
Package scrapegoat provides a public SDK for embedding ScrapeGoat as a library.
Package scrapegoat provides a public SDK for embedding ScrapeGoat as a library.
tests
harness
Package harness provides adversarial HTTP test servers for stress-testing ScrapeGoat.
Package harness provides adversarial HTTP test servers for stress-testing ScrapeGoat.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL