Парсинг даних з GitHub (активність крипто-проектів)
GitHub-активність — один з небагатьох on-chain заміняюваних сигналів фундаментального аналізу крипто-проектів. Кількість коммітів, число активних контрибюторів, частота релізів, швидкість закриття issues — все це публічно доступно та коррелює з реальною розробкою. Сервіси типу Santiment та Electric Capital використовують саме ці метрики як частину developer activity score.
GitHub REST API vs GraphQL API
GitHub надає два API. Для сбору даних про репозиторії краще підходить GraphQL API v4 — дозволяє за один запит отримати дані, на які REST витратив бв 5–10 запитів:
query RepoActivity($owner: String!, $repo: String!) {
repository(owner: $owner, name: $repo) {
stargazerCount
forkCount
defaultBranchRef {
target {
... on Commit {
history(first: 100) {
totalCount
nodes {
committedDate
author { name email }
additions
deletions
}
}
}
}
}
releases(last: 5) {
nodes { tagName createdAt }
}
issues(states: OPEN) { totalCount }
pullRequests(states: MERGED, last: 30) {
nodes { createdAt mergedAt }
}
}
}
Один запит — і ви маєте коммити за 100 останніх днів, releases, open issues, merged PRs. REST API потребував бы окремих запитів до /commits, /releases, /issues, /pulls.
Аутентифікація: Personal Access Token (PAT) з public_repo scope. Без токена rate limit — 60 req/год, з токеном — 5000 req/год для REST, 5000 points/год для GraphQL. PAT створюється через Settings → Developer settings → Fine-grained tokens.
Що саме збирати
Для developer activity dashboard стандартний набір метрик:
| Метрика | Endpoint / поле | Частота сбору |
|---|---|---|
| Commit count (30d/90d) | defaultBranchRef.target.history.totalCount |
Щодня |
| Active contributors | defaultBranchRef.target.history.nodes[].author |
Щодня |
| Code churn (additions + deletions) | history.nodes[].additions/deletions |
Щодня |
| Stars / forks | stargazerCount, forkCount |
Щодня |
| Issues velocity | Open issues + closed last 30d | Щотижня |
| PR merge time (median) | pullRequests.mergedAt - createdAt |
Щотижня |
| Release cadence | Даті останніх releases |
Щотижня |
Contributor deduplication: один разробник може коммітити з різними email. Нормалізація через GitHub login (якщо комміт асоційований з аккаунтом) або fuzzy matching по імені. Боти (Dependabot, renovate, github-actions) потрібно исключати з підрахунку людських контрибюторів.
Обробка rate limits та великої кількості репозиториїв
Crypto-індекс з 200 проектів — кожен з 5–10 репозиториями — це 1000–2000 репозиториїв. При щоденному сборі та 5000 points/год лімітці потрібно управляти бюджетом запитів.
Стоимість GraphQL запиту = sum(requested_nodes). Складний запит з 100 коммітами коштує ~100 points. Для 2000 репозиториїв потрібно ~200k points — це 40 годин при одному PAT токені.
Рішення:
-
Кілька PAT токенів з ротацією. Пул з 10 токенів дає 50k points/год — достатньо для щоденного сбору 2000 репозиториїв.
-
Incremental collection: не збирайте всю історію щоразу. Зберігайте
last_collected_at, запитуйте лише нові коммити черезsinceпараметр. -
Prioritization: "гарячі" репозиторії (висока активність, великий TVL проекту) збираються частіше, "холодні" — раз на тиждень.
import httpx
import asyncio
from collections import deque
class GitHubRateLimiter:
def __init__(self, tokens: list[str]):
self.tokens = deque(tokens)
self.current_remaining = {t: 5000 for t in tokens}
async def get_token(self) -> str:
# Rotate to token with most remaining points
token = max(self.tokens, key=lambda t: self.current_remaining[t])
if self.current_remaining[token] < 100:
await asyncio.sleep(3600) # Wait for reset
return token
async def graphql(self, query: str, variables: dict) -> dict:
token = await self.get_token()
async with httpx.AsyncClient() as client:
resp = await client.post(
"https://api.github.com/graphql",
json={"query": query, "variables": variables},
headers={"Authorization": f"Bearer {token}"},
)
# Update remaining from response headers
cost = resp.json().get("data", {}).get("rateLimit", {}).get("cost", 1)
self.current_remaining[token] -= cost
return resp.json()
Маппінг проектів до репозиториїв
Складання та утримання списку project → github_repos — окрема задача. Джерела:
- Electric Capital Developer Report публікує open-source маппінг проектів до репозиториїв на GitHub
-
DeFiLlama має поле
githubв даних протоколів:GET https://api.llama.fi/protocolsповертає список протоколів з github URL - Manual curation: для нових проектів або проектів з нестандартними github org іменами
Важливий нюанс: крупні проекти (Ethereum, Solana, Uniswap) мають десятки репозиториїв в організації. Суммування активності по всій org потрібно з фільтрацією — repo-зеркала, форки, документаційні репозиторії спотворюють метрики.
Хранення та агрегація
TimescaleDB або ClickHouse для time-series метрик. Схема:
CREATE TABLE github_metrics (
project_id INTEGER,
repo_full_name TEXT,
measured_date DATE,
commits_30d INTEGER,
contributors_30d INTEGER,
additions_30d BIGINT,
deletions_30d BIGINT,
stars INTEGER,
open_issues INTEGER,
PRIMARY KEY (repo_full_name, measured_date)
);
-- Агрегат по проекту (всі його репозиторії)
CREATE VIEW project_dev_activity AS
SELECT project_id, measured_date,
SUM(commits_30d) AS total_commits,
COUNT(DISTINCT repo_full_name) AS active_repos,
SUM(contributors_30d) AS total_contributors
FROM github_metrics
GROUP BY project_id, measured_date;
Нормалізований developer activity score: log(commits + 1) × log(contributors + 1) — логарифмування сглаживает outliers (один проект з 10k commits не повинен домінувати в рейтингу).







