๐ธ๏ธ Scrapyard โ Web Scraper as a Service

English | ะ ัััะบะธะน
Distributed web scraping platform. Schedule scraping jobs via REST API, execute them with Playwright, and analyze results with MongoDB aggregations.
๐ฏ Features
- ๐ฅ๏ธ Web dashboard โ a React SPA to manage jobs, test selectors live, inspect results/diffs/logs, and browse analytics, no curl required
- ๐
Scheduled jobs โ cron expressions for periodic data collection
- ๐งฉ Generic parser โ define CSS selectors via API, no code needed
- ๐ Playwright โ full JavaScript/SPA support
- ๐ Analytics โ MongoDB aggregations for per-job statistics
- ๐ Auto-cleanup โ TTL indexes for old results
- โก Redis caching โ analytics cached for 5min, job lists for 1min
- ๐ API key auth & rate limiting โ optional
X-API-Key header, Redis-backed per-IP limits
- ๐ค Scraping etiquette โ respects
robots.txt, throttles concurrent requests per domain
- ๐ Proxy rotation & circuit breaker โ per-domain proxy pinning, and repeated 403/429s put a domain into cooldown instead of hammering it
- ๐ Browser pooling โ one Chromium instance shared per worker process instead of a fresh launch per scrape
- ๐ Grafana + Prometheus + Alertmanager โ request rate/latency/errors dashboard, Redis/Celery metrics, alert rules for a dead worker/high error rate/stuck jobs
- ๐ญ Distributed tracing โ OpenTelemetry spans across the API, Celery tasks, MongoDB, and Redis, viewable in the bundled Jaeger
- ๐ก๏ธ Global 500 handler โ all unhandled exceptions logged with tracebacks, safe JSON response to clients
- ๐ณ Docker โ one-command startup for all services
๐ ๏ธ Tech Stack
| Component |
Technology |
Why |
| API |
FastAPI (async) |
High performance, auto docs |
| Database |
MongoDB + Motor |
Flexible schemas, async driver |
| Queue |
Celery + Redis |
Reliable task distribution |
| Scraping |
Playwright |
JavaScript rendering support |
| Caching |
Redis |
Fast analytics responses |
| CI/CD |
GitHub Actions |
Tests, linting, coverage |
| Containers |
Docker, docker-compose |
Easy deployment |
๐๏ธ Architecture
โโโโโโโโโโโโโโโ
โ Celery โ
โ Beat โ
โโโโโโโโฌโโโโโโโ
โ schedule jobs
โผ
โโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ
โ Client โโโโโโถโ FastAPI โโโโโโถโ Redis โ
โ โ โ (REST API) โ โ (Broker) โ
โโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โโโโโโโโฌโโโโโโโโ
โฒ โ
โ โผ
โ โโโโโโโโโโโโโโโโโโโ
โ โ Celery Worker โ
โ โ (Playwright) โ
โ โโโโโโโโโโฌโโโโโโโโโ
โ โ
โ โผ
โ โโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ MongoDB โ
โ (jobs, results, โ
โ logs) โ
โโโโโโโโโโโโโโโโโโโ
๐ Quick Start
git clone https://github.com/Artem-Kornilov-pro/scrapyard.git
cd scrapyard
cp .env.example .env
docker-compose up -d
| Service |
URL |
| Web dashboard |
http://localhost:5173 |
| API (Swagger UI) |
http://localhost:8000/docs |
| Prometheus metrics |
http://localhost:8000/metrics |
| Prometheus UI |
http://localhost:9090 |
| Grafana |
http://localhost:3000 (admin / admin) |
| Alertmanager |
http://localhost:9093 |
| Jaeger (traces) |
http://localhost:16686 |
The โScrapyard Overviewโ Grafana dashboard is auto-provisioned (datasource pinned to a fixed uid so re-provisioning never creates a duplicate). It shows request rate by status code, P95 latency, per-endpoint latency, Redis stats, Celery task throughput, worker status, and job counts by status.
Alert rules (docker/prometheus-alerts.yml) cover a dead worker, a worker thatโs up but not draining its queue, a high API error rate, and jobs stuck in error status. docker/alertmanager.yml ships with a no-op receiver โ alerts show up in its UI immediately, add a Slack/webhook receiver there for real notifications.
Tracing (ENABLE_TRACING=true by default in .env.example) exports spans for the API, Celery tasks, MongoDB, and Redis to the bundled Jaeger โ open a trace for a scrape job to see exactly where its time went.
Upgrading an existing .env? New settings land in .env.example over time (proxy rotation, tracing, etc.) but are never added to your own .env automatically. If a feature seems to silently do nothing after pulling updates, diff the two files and copy over whatโs missing:
diff <(grep -o '^[A-Z_]*' .env | sort) <(grep -o '^[A-Z_]*' .env.example | sort)
Frontend development
For hot-reload while working on web/, run it outside Docker against a docker-compose API:
cd web
npm install
npm run dev # http://localhost:5173, proxies /api to localhost:8000
๐ Production checklist
These are off by default for a frictionless local setup, but should be configured before exposing the API publicly:
| Setting |
Default |
Effect |
API_KEY |
unset (auth disabled) |
When set, every /api/v1/* request must send a matching X-API-Key header |
RATE_LIMIT_PER_MINUTE |
120 |
Per-IP request limit on /api/v1/*, backed by Redis; 0 disables it |
RESPECT_ROBOTS_TXT |
true |
Worker checks the target siteโs robots.txt before scraping and skips disallowed URLs |
DOMAIN_THROTTLE_SECONDS |
2.0 |
Minimum gap between scrape requests to the same domain, enforced across all workers via a Redis lock |
SCRAPER_USER_AGENT |
ScrapyardBot/1.0 (+https://github.com/...) |
User-Agent sent by the browser and matched against robots.txt rules |
DRY_RUN_TIMEOUT_SECONDS |
30 |
How long the API waits for a worker to finish a /dry-run before returning 504 |
Redis-backed features (caching, rate limiting, domain throttling) fail open: if Redis is unreachable, the API and workers keep running without that protection rather than going down. /health is never authenticated or rate-limited, so orchestrators can always probe it.
# with API_KEY set
curl http://localhost:8000/api/v1/jobs -H "X-API-Key: <your-key>"
๐ก API Endpoints
Jobs
POST /api/v1/jobs # Create a job
GET /api/v1/jobs # List jobs (with pagination)
GET /api/v1/jobs/{id} # Get job details
PUT /api/v1/jobs/{id} # Update job
DELETE /api/v1/jobs/{id} # Delete job
POST /api/v1/jobs/{id}/pause # Pause job
POST /api/v1/jobs/{id}/resume # Resume job
POST /api/v1/jobs/{id}/run # Run a job immediately, bypassing its schedule
POST /api/v1/jobs/dry-run # Test selectors against a live page without saving a job
GET /api/v1/jobs/{id}/logs # Get job logs
Results
GET /api/v1/jobs/{id}/results # List scrape results (most recent first)
GET /api/v1/jobs/{id}/results/export # Export a run's items as JSON or CSV
GET /api/v1/jobs/{id}/results/diff # Diff two runs (defaults to the two most recent)
Analytics
GET /api/v1/analytics/overview # System overview
GET /api/v1/analytics/jobs/{id}/stats # Per-job statistics
GET /api/v1/analytics/slowest # Top slowest jobs
GET /api/v1/analytics/success-rate # Overall success rate
GET /api/v1/logs # All logs (filterable)
Examples
# Test selectors before saving a job
curl -X POST http://localhost:8000/api/v1/jobs/dry-run \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/products",
"selectors": {
"items": "div.product-card",
"fields": {"title": {"selector": "h3.title", "attr": "text"}}
}
}'
# Create a scraping job โ notify_webhook fires once the job hits 5
# consecutive failures; diff_key matches items across runs for /diff
curl -X POST http://localhost:8000/api/v1/jobs \
-H "Content-Type: application/json" \
-d '{
"name": "Product Prices",
"url": "https://example.com/products",
"selectors": {
"items": "div.product-card",
"fields": {
"title": {"selector": "h3.title", "attr": "text"},
"price": {"selector": "span.price", "attr": "text", "transform": "strip_currency"}
}
},
"schedule": "0 */6 * * *",
"diff_key": "title",
"notify_webhook": "https://hooks.example.com/scrapyard-alerts"
}'
# Run it right now instead of waiting for the schedule
curl -X POST http://localhost:8000/api/v1/jobs/{id}/run
# See what changed since the last run
curl http://localhost:8000/api/v1/jobs/{id}/results/diff
# Export the latest run as CSV
curl http://localhost:8000/api/v1/jobs/{id}/results/export?format=csv
# Get analytics overview
curl http://localhost:8000/api/v1/analytics/overview
๐ Project Structure
scrapyard/
โโโ api/ # FastAPI application
โ โโโ core/ # Config, database, cache
โ โโโ models/ # Pydantic models
โ โโโ routes/ # API endpoints
โ โโโ services/ # Business logic
โ โโโ tests/ # API tests
โโโ worker/ # Celery worker
โ โโโ engines/ # Playwright engine, browser pool, parsers
โ โโโ tasks/ # Celery tasks (scraper, dry-run, scheduler)
โ โโโ utils/ # Robots.txt, throttling, proxy, circuit breaker
โ โโโ tests/ # Worker tests
โโโ web/ # React + TypeScript dashboard (Vite)
โ โโโ src/
โ โโโ api/ # Typed API client
โ โโโ components/ # Shared UI
โ โโโ hooks/ # React Query hooks
โ โโโ pages/ # Jobs, job detail, new/edit job, analytics
โโโ e2e/ # Smoke tests against a live docker-compose stack
โโโ scripts/ # Benchmark script
โโโ docker/ # Dockerfiles + Prometheus/Alertmanager/Grafana config
โโโ .github/workflows/ # CI/CD
โโโ docker-compose.yml
โโโ requirements.txt
โโโ README.md
๐ค Contributing
See CONTRIBUTING.md for contribution guidelines.
๐ License
This project is licensed under the MIT License โ see LICENSE for details.
่ฏ่ฎบ