بنقرة واحدة
data-collection
Parallel data collection from web sources, APIs, and documentation sites
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Parallel data collection from web sources, APIs, and documentation sites
التثبيت باستخدام 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.
Deploy static sites to GitHub Pages via API — create repo, push, enable Pages, all from CLI
Build knowledge bases from collected data — clean raw files, generate search indexes, deploy GitHub Pages websites, and package as Hermes skills. Covers the full pipeline from raw READMEs/docs to searchable open-source knowledge bases.
| name | data-collection |
| description | Parallel data collection from web sources, APIs, and documentation sites |
| version | 1.0.0 |
| author | Hermes Agent |
| license | MIT |
| platforms | ["linux"] |
| metadata | {"hermes":{"tags":["data-collection","web-scraping","parallel-processing","python","multiprocessing"],"related_skills":["web-tool-builder","flask-web-tools","coding-principles"]}} |
| triggers | ["data collection","web scraping","crawl","采集","爬虫","parallel collection"] |
Reusable patterns for collecting data from web sources, APIs, and documentation sites. Optimized for multi-core servers.
When to use: Collecting from multiple independent sources simultaneously.
Key insight: Use multiprocessing.Process (not threads) for true parallelism on multi-core servers. Each process maintains its own state file, with a shared counter for progress tracking.
from multiprocessing import Process, Manager, Lock, Value
import signal, sys, json
from pathlib import Path
# Shared counter (atomic via Lock)
shared_counter = Value('i', 0)
lock = Lock()
stop_event = multiprocessing.Event()
# Each process has its own seen-state file
def init_process_seen(process_name):
seen_file = BASE_DIR / f"seen_{process_name}.json"
if seen_file.exists():
data = json.loads(seen_file.read_text())
return set(data.get("urls", [])), set(data.get("contents", []))
return set(), set()
def save_process_seen(process_name, seen_urls, seen_contents):
seen_file = BASE_DIR / f"seen_{process_name}.json"
data = {"urls": list(seen_urls), "contents": list(seen_contents)}
seen_file.write_text(json.dumps(data, indent=2))
# Process function
def process_source(shared_counter, lock, stop_event):
process_name = "source_name"
seen_urls, seen_contents = init_process_seen(process_name)
session = create_session()
while not stop_event.is_set():
# Collect data...
with lock:
shared_counter.value += 1
# Periodic save
if shared_counter.value % 50 == 0:
save_process_seen(process_name, seen_urls, seen_contents)
# Sleep with interrupt check
for _ in range(interval):
if stop_event.is_set():
break
time.sleep(1)
# Signal handling for graceful shutdown
def signal_handler(signum, frame):
stop_event.set()
for p in processes:
p.join(timeout=30)
if p.is_alive():
p.terminate()
sys.exit(0)
signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGINT, signal_handler)
Manager().list() returns ListProxy which doesn't have .add() methodManager().set() works but adds IPC overhead for every operationrequests + gzip: Don't Manually DecompressProblem: Manual gzip.decompress(resp.content) fails when server sends plain JSON with Content-Encoding: gzip header.
Solution: Use resp.text — requests handles decompression automatically.
# ❌ WRONG - crashes on plain JSON responses
if resp.headers.get("Content-Encoding") == "gzip":
content = gzip.decompress(resp.content).decode("utf-8")
else:
content = resp.text
# ✅ CORRECT - requests handles it
content = resp.text
Why it happens: Some servers (like GitHub API) send Content-Encoding: gzip header but the actual content is plain JSON. requests transparently decompresses when using .text, but .content returns raw bytes.
multiprocessing.Manager().list() is ListProxyProblem: Manager().list() returns a ListProxy object, not a real list.
# ❌ WRONG - ListProxy has no .add()
shared_urls = manager.list()
shared_urls.add(url) # AttributeError!
# ✅ CORRECT - use per-process state or Manager().dict()
# Option A: Per-process state (recommended for high-throughput)
# Option B: Manager().dict() with manual set operations
shared_urls = manager.dict()
shared_urls[url_hash] = True
Problem: Fixed URL list + hash-based dedup = first round collects everything, subsequent rounds do nothing.
Solution:
# Extract repo links from trending page
repos = re.findall(r'href=["\'](/[^/]+/[^"\']+)["\']', content)
repos = [r for r in repos if r.count("/") == 2 and not r.startswith("/trending")]
# Then fetch README from raw.githubusercontent.com
# Search repositories by topic
url = f"https://api.github.com/search/repositories?q={topic}&sort=stars&per_page=10"
# Rate limit: 10 requests/minute for unauthenticated, 30 for authenticated
# Extract article links with date patterns
article_patterns = [
r'/\d{4}/\d{2}/', # Date format
r'/blog/', r'/article/', r'/post/', r'/tutorial/',
]
# Scan collected files for new links
all_links = set()
for doc_file in collected_dir.glob("*.md"):
content = doc_file.read_text()
links = extract_links(content, "")
all_links.update(links)
multi-process-scraper — More complete reference with watchdog, size monitoring, scaling guide, and pitfalls