Grubの特長
主要クローラーの機能を統合し、さらに他にはない機能を追加しました。
セルフホスト型クローラー
クラウド/マネージドクローラー
Ghost Protocolを持つのはGrubだけ – 標準クローリングが失敗した場合に、ブロックされたページのスクリーンショットを撮影し、LLMを介してコンテンツを抽出する自動ビジョンベースのフォールバックです。予防(Camoufox + プロキシ + ステルス)で95%のブロックを処理し、残りをGhost Protocolが処理します。
APIエンドポイント
コアクローリング
エージェント(モードB)
ジョブ管理
リモートキャッシュ
セッション管理
ライブストリーム
メッシュ
システム
MCPツール(grub-crawl.py)
MCPブリッジは、すべての機能を任意のMCP互換ホストに公開します:
内部モジュール
エージェントコア(app/agent/)
プロバイダアダプター(app/agent/providers/)
ポリシーゲート(app/policy/)
可観測性(app/observability/)
APIレイヤー
アンチディテクション(app/)
| ファイル | 目的 | 状態 |
|---|
stealth.py | playwright-stealthパッチ、トラッカードメインブロッキング | 完了 |
proxy.py | 環境変数フォールバック付きリクエストごとのプロキシ解決 | 完了 |
メッシュ(app/mesh/)
インフラストラクチャ
エージェントステートマシン```
INIT -> PLAN -> EXECUTE_TOOL -> OBSERVE -> PLAN -> ... -> RESPOND -> STOP
| |
+-- policy_denied ---------------------->+
+-- max_steps / max_wall_time / max_failures -> STOP
+-- no_op_loop (3x empty) ------------> STOP
+-- blocked (ghost trigger) -----------> GHOST -> OBSERVE
Stop conditions enforced every iteration:
- `max_steps`(デフォルト: 12)
- `max_wall_time`(デフォルト: 90秒)
- `max_failures`(デフォルト: 3)
- `no_op_loop`(3回連続の空の応答)
- `policy_denied`(ブロックされたツール/ドメイン)
- `completed`(エージェントがテキストで応答)
## 検出回避
積み重なる3層の検出回避。防止策はブロックが発生する前に阻止します。ゴーストプロトコルはその後に処理します。
### Camoufoxエンジン
プラグイン可能な検出回避ブラウザで、C++レベルのフィンガープリント偽装を備えています。手動のユーザーエージェントトリックは不要 — Camoufoxはブラウザレベルでコンテキストごとにリアルなフィンガープリントを生成し、キャンバス、WebGL、フォント、ナビゲータプロパティなどを含みます。```bash
# Switch engine (default: chromium)
BROWSER_ENGINE=camoufox
Per-Request Proxy
クロールトラフィックを住宅用、データセンター用、またはカスタムプロキシプール経由でルーティングします。環境変数ベースのデフォルト設定をリクエストごとに上書き可能。Playwrightと完全互換のプロキシ設定。```bash
Env-based default
PROXY_SERVER=http://proxy.example.com:10001
PROXY_USERNAME=your_username
PROXY_PASSWORD=your_password
Or per-request
curl -X POST http://localhost:6792/api/crawl
-H "Content-Type: application/json"
-d '{
"url": "https://example.com",
"options": {
"proxy": {
"server": "http://proxy.example.com:10001",
"username": "your_username",
"password": "your_password"
}
}
}'
### ステルスモード
オプトイン `playwright-stealth` パッチ (Chromium用、Camoufoxでは組み込みのためスキップ)。20以上のトラッキング/分析ドメイン (Google Analytics、DataDome、PerimeterXなど) をブロックし、指紋情報の表面を減らします。```bash
STEALTH_ENABLED=true
BLOCK_TRACKING_DOMAINS=true
ゴーストプロトコル
クロール結果がアンチボットブロック(Cloudflareチャレンジ、CAPTCHA、空のSPAシェル)を示した場合、エージェントはクロークモードに切り替えることができます:
- Playwrightを使用して全ページスクリーンショットを撮る
- 画像を視覚対応LLM(Claude SonnetまたはGPT-4o)に送信する
- レンダリングされたピクセルからコンテンツを抽出する
- トレースに
render_mode: "ghost"を含めて抽出されたテキストを返す
これにより、DOMベースのアンチボット検出を完全に回避します。
AGENT_GHOST_ENABLED=trueが必要です。AGENT_GHOST_AUTO_TRIGGER=trueの場合、検出されたブロックで自動トリガーされます。
メッシュ
エージェント同士の会話。各Grubインスタンスはワーカーでありコーディネーターでもあります。ローカルノードはクラウドにオフロードし、クラウドはローカルに委任します。ツールコールは透過的にワイヤを越えます。```
Node A (local) Node B (cloud)
┌─────────────┐ ┌─────────────┐
│ AgentEngine │ │ AgentEngine │
│ ↓ │ │ ↓ │
│ MeshDispatcher ──── HTTP ────→ MeshDispatcher │
│ ↓ │ │ ↓ │
│ Dispatcher │ │ Dispatcher │
│ ↓ │ │ ↓ │
│ ToolRegistry │ │ ToolRegistry │
└─────────────┘ └─────────────┘
↕ heartbeat (15s) ↕
└────────────────────────────────┘
**動作原理:**
- **発見** — ノードはシードピアリストを介して参加し、その後ゴシップ(1ホップ)で他のノードを学習します
- **ハートビート** — 15秒ごとにノードが負荷メトリクスを交換します。3回見逃すと異常と判断。2分で削除されます
- **ルーティング** — MeshDispatcherは負荷、ローカリティ、アフィニティに基づいて全ノードをスコアリングし、ツール呼び出しを最適なノードにルーティングします
- **最大1ホップ** — ノードA→Bのみ、A→B→Cは不可。ルーティングループを防止します
- **ローカルフォールバック** — リモート実行が失敗した場合、ローカルのDispatcherにフォールバックします
- **HMAC認証** — すべてのメッシュトラフィックは共有シークレットで署名されます(SHA-256、TTL60秒)
### ローカルで2ノードメッシュを実行する```bash
# Docker Compose (recommended)
./deploy.sh mesh # Linux/Mac
./deploy.ps1 -Target mesh # Windows
# Verify
curl http://localhost:6792/mesh/peers # Node A sees Node B
curl http://localhost:6793/mesh/peers # Node B sees Node A
ローカルをCloud Runに接続する```bash
Deploy to Cloud Run with mesh
./deploy.sh cloudrun latest --mesh-peer http://your-local-ip:6792 --mesh-secret mysecret
Start local node
MESH_ENABLED=true MESH_SECRET=mysecret MESH_PEERS=https://your-cloud-run-url
MESH_ADVERTISE_URL=http://your-local-ip:6792
uvicorn app.main:app --port 6792
### 手動設定```bash
# Node A
MESH_ENABLED=true MESH_NODE_NAME=local MESH_SECRET=test123 \
MESH_ADVERTISE_URL=http://localhost:6792 \
uvicorn app.main:app --port 6792
# Node B
MESH_ENABLED=true MESH_NODE_NAME=cloud MESH_SECRET=test123 \
MESH_PEERS=http://localhost:6792 \
MESH_ADVERTISE_URL=http://localhost:8081 \
uvicorn app.main:app --port 8081
メッシュが無効の場合(MESH_ENABLED=false、デフォルト)、Grubはメッシュのオーバーヘッドがゼロの通常のシングルノードクローラとして動作します。
ライブストリーム
クローラの動作をリアルタイムで監視します。持続的なウォームChromiumインスタンスのプールが、WebSocketまたはMJPEGを介してビューポートフレームをストリーミングします。
WebSocket — 接続して対話型コマンドを送信:```javascript
const ws = new WebSocket("ws://localhost:6792/stream/my-session?url=https://example.com");
ws.onmessage = (e) => {
const msg = JSON.parse(e.data);
if (msg.type === "frame") document.getElementById("viewport").src = "data:image/jpeg;base64," + msg.data;
};
// Navigate, click, scroll, type — all over the same socket
ws.send(JSON.stringify({ action: "navigate", url: "https://example.com/pricing" }));
ws.send(JSON.stringify({ action: "click", selector: "#signup-btn" }));
ws.send(JSON.stringify({ action: "scroll", direction: "down" }));
**MJPEG** — ``タグに入れるだけで、即座にビデオが表示されます:```html
<img src="http://localhost:6792/stream/my-session/mjpeg?url=https://example.com" />
BROWSER_STREAM_ENABLED=true が必要です。各Chromiumインスタンスは約150~300MBのRAMを使用します。
クイックスタート
ローカル開発```bash
git clone
cd grub-crawl
cp .env.example .env
pip install -r requirements.txt
uvicorn app.main:app --reload --host 0.0.0.0 --port 6792
### Agent Mode B を有効にする```bash
# Add to .env
AGENT_ENABLED=true
OPENAI_API_KEY=sk-...
# or
ANTHROPIC_API_KEY=sk-ant-...
AGENT_PROVIDER=anthropic
エージェントタスクの送信```bash
curl -X POST http://localhost:6792/api/agent/run
-H "Content-Type: application/json"
-d '{
"task": "Find the pricing page on example.com and extract plan details",
"max_steps": 10,
"allowed_domains": ["example.com"]
}'
### Docker```bash
# Single node
./deploy.sh local # or ./deploy.ps1 -Target local
# 2-node mesh
./deploy.sh mesh # or ./deploy.ps1 -Target mesh
# Cloud Run
./deploy.sh cloudrun v1.0.0 # or ./deploy.ps1 -Target cloudrun -Tag v1.0.0
# Cloud Run + mesh (connect to local node)
./deploy.sh cloudrun v1.0.0 --mesh-peer http://your-ip:6792 --mesh-secret mykey
アンチ検出 (Camoufox + Proxy)```bash
Add to .env
BROWSER_ENGINE=camoufox
STEALTH_ENABLED=true
BLOCK_TRACKING_DOMAINS=true
Optional: proxy
PROXY_SERVER=http://proxy.example.com:10001
PROXY_USERNAME=your_username
PROXY_PASSWORD=your_password
### Ghost Protocol (ボット対策回避)```bash
# Add to .env
AGENT_GHOST_ENABLED=true
curl -X POST http://localhost:6792/api/agent/ghost \
-H "Content-Type: application/json" \
-d '{"url": "https://blocked-site.com"}'
ライブブラウザストリーム```bash
Add to .env
BROWSER_STREAM_ENABLED=true
BROWSER_POOL_SIZE=2
MJPEG (open in browser)
open "http://localhost:6792/stream/demo/mjpeg?url=https://example.com"
## 設定
### サーバー
- `HOST` (default: 0.0.0.0)
- `PORT` (default: 6792)
- `DEBUG` (default: false)
### ストレージ
- `STORAGE_PATH` (default: ./storage)
- `RUNNING_IN_CLOUD` (default: false)
- `GCS_BUCKET_NAME`
- `GOOGLE_CLOUD_PROJECT`
### 認証
- `DISABLE_AUTH` (default: false)
- `GNOSIS_AUTH_URL` (default: http://gnosis-auth:5000)
### ブラウザエンジン
- `BROWSER_ENGINE` — chromium | camoufox (default: chromium)
### クローリング
- `MAX_CONCURRENT_CRAWLS` (default: 5)
- `CRAWL_TIMEOUT` (default: 30)
- `ENABLE_JAVASCRIPT` (default: true)
- `ENABLE_SCREENSHOTS` (default: false)
### プロキシ
- `PROXY_SERVER` — proxy URL (例: http://proxy:10001)
- `PROXY_USERNAME`
- `PROXY_PASSWORD`
- `PROXY_BYPASS` — カンマ区切りのバイパスリスト
### ステルス
- `STEALTH_ENABLED` (default: false) — playwright-stealth パッチ
- `BLOCK_TRACKING_DOMAINS` (default: false) — アナリティクス/トラッキングリクエストをブロック
### エージェント(モードB)
- `AGENT_ENABLED` (default: false)
- `AGENT_MAX_STEPS` (default: 12)
- `AGENT_MAX_WALL_TIME_MS` (default: 90000)
- `AGENT_MAX_FAILURES` (default: 3)
- `AGENT_ALLOWED_TOOLS` — カンマ区切りの許可リスト
- `AGENT_ALLOWED_DOMAINS` — カンマ区切りの許可リスト
- `AGENT_BLOCK_PRIVATE_RANGES` (default: true)
- `AGENT_REDACT_SECRETS` (default: true)
### LLMプロバイダー
- `AGENT_PROVIDER` — openai | anthropic | ollama (default: openai)
- `OPENAI_API_KEY`
- `OPENAI_MODEL` (default: gpt-4.1-mini)
- `ANTHROPIC_API_KEY`
- `ANTHROPIC_MODEL` (default: claude-3-5-sonnet-latest)
- `OLLAMA_BASE_URL` (default: http://localhost:11434)
- `OLLAMA_MODEL` (default: llama3.1:8b-instruct)
### ゴーストプロトコル
- `AGENT_GHOST_ENABLED` (default: false)
- `AGENT_GHOST_AUTO_TRIGGER` (default: true)
- `AGENT_GHOST_VISION_PROVIDER` — AGENT_PROVIDER から継承
- `AGENT_GHOST_MAX_IMAGE_WIDTH` (default: 1280)
### メッシュ
- `MESH_ENABLED` (default: false) — マスタースイッチ
- `MESH_PEERS` — カンマ区切りのシードピアURL
- `MESH_NODE_NAME` — 人間が読める名前 (default: hostname)
- `MESH_SECRET` — ノード間認証用の共有HMACシークレット
- `MESH_ADVERTISE_URL` — 他のピアがこのノードに到達するためのURL
- `MESH_PREFER_LOCAL` (default: true) — ローカル実行を優先
- `MESH_HEARTBEAT_INTERVAL_S` (default: 15)
- `MESH_PEER_TIMEOUT_S` (default: 45) — これを過ぎると異常とマーク
- `MESH_PEER_REMOVE_S` (default: 120) — これを過ぎるとピアテーブルから削除
- `MESH_REMOTE_TIMEOUT_MS` (default: 35000) — リモートツール呼び出しのタイムアウト
### ライブストリーム
- `BROWSER_POOL_SIZE` (default: 1)
- `BROWSER_STREAM_ENABLED` (default: false)
- `BROWSER_STREAM_QUALITY` (default: 25) — JPEG品質 1-100
- `BROWSER_STREAM_MAX_WIDTH` (default: 854)
- `BROWSER_STREAM_MAX_LEASE_SECONDS` (default: 300)
## レスポンス契約
`POST /api/markdown` returns:
`success`, `url`, `final_url`, `status_code`, `markdown`, `markdown_plain`, `content`, `render_mode`, `wait_strategy`, `timings_ms`, `blocked`, `block_reason`, `captcha_detected`, `http_error_family`, `body_char_count`, `body_word_count`, `visible_char_count`, `visible_word_count`, `visible_similarity`, `quarantined`, `quarantine_reason`, `policy_flags`, `content_quality`, `extractor_version`, `normalized_url`, `content_hash`
### コンテンツ品質
- `blocked` — アンチボット/キャプチャ/チャレンジ
- `empty` — 非常に低いシグナル
- `minimal` — 薄い/エラーページ
- `sufficient` — 要約に使用可能
`content_quality == "sufficient"` でない限り要約しないでください。
### プロンプトインジェクション防御
- `quarantined=true` は、抽出されたコンテンツに、ページの可視レンダリングテキストには存在しない指示のようなテキストが検出されたことを意味します(`.sr-only` / 視覚的に隠された悪用によく見られます)。
- 隔離された場合、`content_quality` は `minimal` にダウングレードされ、`policy_flags` には `hidden_text_suspected` と `quarantined` が含まれ、`content`/`markdown` の出力は空になります(フェイルクローズド)。
### エラーフォーマット```json
{"error": "http_error|validation_error|internal_error", "status": 400, "details": {}}
Benchmarks
戦闘アリーナ — Crawl4AI、Firecrawl(セルフホスト)、Scrapyとの直接対決ベンチマーク。すべてのテストは同じマシン、同じURL、同じ条件で実行。Grubはベースラインとして最初に実行され、残りのアダプターはレート制限バイアスを防ぐためにランダム順序で、各間に10秒の遅延を入れて実行されます。
単一URL速度(ms、低いほど良い)
Grubは単一URL速度レースで4/5勝利。Markdown変換はネイティブRustエンジン(grub_md)により0~21msで実行。
Grubフェーズ内訳(サーバーサイドms)
ナビゲーションが支配的。Rustエンジンのおかげで、ほとんどのページでMarkdown変換は1ミリ秒未満。
バッチスループット(ms、低いほど良い)
Grubは2/3のバッチサイズで勝利。URLあたりコスト:163-312ms(Grub)対255-477ms(その他)。
実行方法```bash
Start Grub
docker compose up -d
Start Firecrawl (optional)
docker compose -f combat/firecrawl-compose.yaml up -d
Install combat deps
pip install crawl4ai scrapy markdownify tabulate
Run the arena
pytest combat/ -m combat -v
Generate report
python -m combat.report
## 開発状況
### フェーズ1: コアインフラストラクチャ ✅
### フェーズ2: クローリング ✅
### フェーズ3: エージェントモジュール ✅
- [x] エージェントコア — ステートマシン、型、エラー (W1)
- [x] 統合ツールコントラクト — タイムアウト/リトライ付きディスパッチャ (W2)
- [x] ポリシーゲート — ドメイン許可リスト、プライベートレンジ拒否、編集 (W3)
- [x] 可観測性 — EventBus、TraceCollector、RunSummaryの永続化 (W4)
- [x] API配線 — `/api/agent/run`、`/api/agent/status`、JobType.AGENT_RUN (W5)
- [x] プロバイダアダプタ — OpenAI、Anthropic、Ollama(フォールバック付き) (W6)
- [x] 設定フラグ — agent、provider、ghost、stream設定 (W7)
### フェーズ4: ゴーストプロトコル ✅
- [x] クロークモードトリガー検出 (W8)
- [x] スクリーンショットキャプチャパイプライン (W8)
- [x] Claude/GPT-4oによるビジョン抽出 (W8)
- [x] エンジン内のフォールバックチェーン (W8)
- [x] 外部呼び出し元向けゴーストツール (W8)
- [x] Ghost MCPツール + RESTエンドポイント (W8)
### フェーズ5: ライブブラウザストリーム ✅
- [x] リース/返却機能付き永続ブラウザプール (W9)
- [x] CDPスクリーンキャストリレー (W9)
- [x] インタラクティブコマンド対応WebSocketエンドポイント (W9)
- [x] MJPEGフォールバックストリーム (W9)
- [x] ストリームステータス + プールステータスエンドポイント (W9)
### フェーズ5.5: 検出回避 ✅
- [x] Camoufox検出回避ブラウザエンジン (W10)
- [x] リクエストごとのプロキシ(envフォールバック付き) (W10)
- [x] Chromium向けステルスパッチ (W10)
- [x] トラッカー/アナリティクスドメインブロッキング (W10)
- [x] Anthropicビジョン形式検出の修正 (W10)
### フェーズ6: メッシュコーディネータ ✅
- [x] ゴシッププロトコルによるピア発見(1ホップ) (W11)
- [x] HMAC-SHA256によるノード間認証 (W11)
- [x] 負荷メトリクス+シードリトライ付きハートビートループ (W11)
- [x] MeshDispatcher — 透過的なノード間ツールルーティング (W12)
- [x] ロケール/アフィニティボーナス付き負荷ベーススコアリング (W12)
- [x] デプロイスクリプト — ローカル、メッシュ、Cloud Run (W12)
- [x] Docker Compose 2ノードメッシュトポロジ (W12)
- [x] 組み込みランディングページ(grub-site) (W12)
### フェーズ7: パフォーマンス+堅牢化
- [x] Rustマークダウンエンジン(`grub_md`) — PyO3ネイティブ拡張、サブミリ秒変換
- [x] コンバットアリーナ — Crawl4AI、Firecrawl、Scrapyに対する自動ベンチマーク
- [x] ユニットテストスイート — 全モジュールにわたる176テスト
- [ ] エラーハンドリングの改善
- [ ] 監視とアラート
完全なアーキテクチャ計画については[MASTER_PLAN.md](https://github.com/deepbluedynamics/grubcrawler/blob/HEAD/MASTER_PLAN.md)を参照してください。
## ライセンス
Grub Crawler Project ライセンス