ワンクリックで
multi-process-scraper
Build high-throughput multi-process Python scrapers/collectors for small servers
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Build high-throughput multi-process Python scrapers/collectors for small servers
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Delegate coding to OpenAI Codex CLI (features, PRs).
Configure, extend, or contribute to Hermes Agent.
Manage multiple remote servers from Hermes via SSH — deploy services, configure firewalls, transfer files, run commands across servers
Clone/create/fork repos; manage remotes, releases.
Parallel data collection from web sources, APIs, and documentation sites
Deploy static sites to GitHub Pages via API — create repo, push, enable Pages, all from CLI
| name | multi-process-scraper |
| description | Build high-throughput multi-process Python scrapers/collectors for small servers |
| tags | ["python","scraper","multiprocessing","web-scraping","data-collection"] |
| triggers | ["building a web scraper or data collector","need to scrape many URLs in parallel","multi-process Python scraping","collector architecture"] |
Build high-throughput data collectors that maximize CPU/network utilization on small servers (2C2G+).
main.py
├── worker_type_A × N (e.g. 10 trending scrapers)
├── worker_type_B × N (e.g. 10 search scrapers)
├── worker_type_C × N (e.g. 10 docs scrapers)
└── watchdog.sh (cron, auto-restart)
Each worker is an independent Process with its own:
manager = Manager()
counter = manager.Value('i', 0) # shared atomic counter
lock = manager.Lock()
stop = manager.Event()
Do NOT use Manager.list() or Manager.set() for seen-URLs — they're slow (proxy overhead on every .add()). Each process maintains its own local set() and saves to its own JSON file.
process_seen = {} # {name: {"urls": set(), "contents": set()}}
def collect(url, ...):
uh = url_hash(url)
if uh in process_seen[name]["urls"]:
return False
process_seen[name]["urls"].add(uh)
# ... fetch and save ...
Cross-process dedup is optional (check other processes' seen files) but adds complexity. Per-process dedup is fast and sufficient — duplicate files are cheap.
Split work across N identical workers by PID modulo:
# 4 docs workers share 17 URLs
batch = TECH_DOCS[pid::4] # worker 0 gets [0,4,8,12], worker 1 gets [1,5,9,13], ...
For search/trending: each worker picks random topics independently.
while not stop.is_set():
do_work()
save_seen()
for _ in range(60): # 60 seconds between rounds
if stop.is_set(): break
time.sleep(1)
Check stop every second so SIGTERM is responsive.
# WRONG — causes BadGzipFile on API responses
if resp.headers.get("Content-Encoding") == "gzip":
content = gzip.decompress(resp.content).decode()
# RIGHT — just use resp.text
content = resp.text
#!/bin/bash
# collector/watchdog.sh — run via cron every 5 min
HOST="hz-server"
MIN_PROCESSES=20
COUNT=$(ssh $HOST "ps aux | grep main_v | grep -v grep | wc -l")
if [ "$COUNT" -lt "$MIN_PROCESSES" ]; then
ssh $HOST "kill -9 \$(ps aux | grep main_v | grep awk...) 2>/dev/null"
ssh $HOST "cd /opt/collector && nohup python3 main_v4.py > /dev/null 2>&1 &"
fi
Cron job setup:
cronjob(action='create', no_agent=True, script='collector/watchdog.sh', schedule='*/5 * * * *')
| Server | Processes | Threads/proc | Expected throughput |
|---|---|---|---|
| 2C2G | 20 | 4 | ~200 files/hour |
| 2C4G | 50 | 4 | ~500 files/hour |
| 4C8G | 100 | 8 | ~2000 files/hour |
Memory per process: ~25-40MB. Keep total < 80% of RAM.
⚠️ CRITICAL: Do NOT exceed the table above. 100 processes on 2C2G will crash the server completely — SSH becomes unreachable, requiring a hard reboot via cloud console. Always start conservative (20) and scale up only after confirming memory headroom.
Track data growth and notify at intervals (e.g. every 100MB). Use a state file to remember the last checkpoint:
#!/bin/bash
# collector/size_monitor.sh — run via cron every 5 min
STATE_FILE="/tmp/collector_size_state"
CURRENT=$(ssh hz-server "du -sm /opt/collector/data/ | awk '{print \$1}'" 2>/dev/null)
LAST=0
[ -f "$STATE_FILE" ] && LAST=$(cat "$STATE_FILE")
DIFF=$((CURRENT - LAST))
if [ $DIFF -ge 100 ]; then
echo "$CURRENT" > "$STATE_FILE"
echo "📊 采集进度: ${CURRENT}MB / 1000MB"
fi
# Empty output = silent (no notification)
The watchdog should ONLY output when something is wrong. In no_agent cron mode, empty stdout = no message sent to user.
#!/bin/bash
# collector/watchdog.sh — only outputs on failure
HOST="hz-server"
MIN_PROCESSES=20
COUNT=$(ssh -o ConnectTimeout=5 $HOST "ps aux | grep main_v | grep -v grep | wc -l" 2>/dev/null)
if [ -z "$COUNT" ] || [ "$COUNT" -lt "$MIN_PROCESSES" ]; then
echo "⚠️ 进程异常: $COUNT 个,正在重启..."
ssh $HOST "kill -9 \$(ps aux | grep main_v | grep -v grep | awk '{print \$2}') 2>/dev/null"
ssh $HOST "cd /opt/collector && nohup python3 main_v4.py > /dev/null 2>&1 &"
sleep 3
NEW=$(ssh $HOST "ps aux | grep main_v | grep -v grep | wc -l" 2>/dev/null)
echo "✅ 已重启: $NEW 个进程"
fi
Setup with no_agent cron (no token consumption):
cronjob(action='create', no_agent=True, script='collector/watchdog.sh', schedule='*/5 * * * *')
Manager.list().add() is SLOW: Use per-process local sets, not shared proxies.stop_event.set() + join(timeout=10) before terminate().references/collector-v4.py for the full working v4.0 code (50-process version)references/watchdog.sh for the watchdog script