GitHub仓库活跃度评估:Python+API批量生成Markdown报告
发布时间:2026/9/28 15:42:03来源:尧图网络
一个项目即便很久没有大版本更新只要维护者还在持续提交、Issue 有人回应、Release 节奏稳定就一定还有一批人愿意跟着继续“玩”。这种信任感比短期热度更能说明问题。最近看到社区里有人感慨“时隔那么久还有小伙伴愿意一起玩”这其实是开源项目最值钱的状态长期维护、社区认同、选型风险低。这次我们不替某个具体项目站台而是写一个可以直接落地的开源仓库活跃度评估脚本用 Python 调用 GitHub API批量拉取仓库的 Star、Fork、最近 Push、最近 Release、License 等数据最后生成一份 Markdown 报告帮你判断哪些项目值得长期投入、哪些项目可能已经停止维护。脚本核心能力可以提前说纯命令行执行、不需要 GPU、CPU 和内存占用都很低、支持读取 TXT 或 CSV 形式的仓库列表、支持批量分析、最终输出表格化报告、全程走 GitHub 官方 REST API。整个过程不影响本地其他任务适合放进定时任务或 CI 流水线。如果你正在做技术选型、需要评估一批开源依赖的维护状态或者想给团队做一个“开源项目健康度周报”本文这套脚本可以直接改来用。1. 核心能力速览能力项说明项目类型开源仓库活跃度评估脚本主要功能批量拉取 GitHub 仓库元数据、Release、Open Issues生成 Markdown 报告开发语言Python 3.8依赖库requests硬件要求无 GPU 要求普通 CPU、1GB 内存即可支持平台Windows / Linux / macOS启动方式命令行运行是否支持批量任务支持读取 TXT 或 CSV 仓库列表是否提供 API使用 GitHub REST API脚本本身可作为 API 调用工具输出格式Markdown 报告文件适合场景技术选型评估、开源依赖维护状态巡检、社区项目活跃度分析脚本本身不涉及模型推理也不依赖显卡所以“显存占用”在这里不适用。真正需要关注的资源是网络请求次数和 GitHub API 配额。2. 适用场景与使用边界2.1 适合谁技术负责人选型前评估开源库的维护活性避免引入半年不更新的依赖。后端开发批量检查项目依赖的上游仓库是否还有 Release。开源社区运营定期输出项目活跃度周报观察社区走势。开发者个人判断一个 Star 很多的仓库是否真的有人在维护。2.2 能解决什么问题把“感觉上很火”变成“数据上可比较”。用最近 Push、最近 Release、Open Issues、License 等信息对仓库做初步体检。批量分析几十个仓库时比手动打开网页逐个看高效得多。生成统一格式的报告方便团队内部共享和留档。2.3 不适合什么场景不能判断代码质量、安全隐患、架构合理性。不能预测项目未来走向活跃度只是参考维度之一。不能替代 Code Review 和依赖审计。不适合分析私有仓库因为脚本默认走公开仓库 API私有仓库需要更复杂的认证和授权。2.4 使用边界与合规提醒使用 GitHub API 前建议阅读 GitHub 服务条款和 API 文档。获取的仓库元数据、License 信息只用于技术评估不要做商业转售或大规模抓取。如果用脚本分析第三方项目不要伪造 Issue、Release 数据也不要干扰目标仓库。如果需要基于开源项目做二次开发或商用务必确认仓库的 License 条款。个人访问 Token 属于敏感信息不要提交到公共仓库。3. 环境准备与前置条件3.1 操作系统脚本是纯 Python 实现Windows、Linux、macOS 都可以运行。只要 Python 环境可用不依赖系统特定命令。3.2 Python 版本建议 Python 3.8 及以上。脚本使用了 f-string、类型提示等语法低版本需要自行调整。先检查本机 Python 版本python --version如果输出 Python 3.8.10 或更高版本就可以继续。3.3 依赖安装脚本只需要requests库。建议先创建虚拟环境避免污染全局 Python 环境。# Linux / macOS python3 -m venv venv source venv/bin/activate pip install -r requirements.txt # Windows PowerShell python -m venv venv venv\Scripts\activate pip install -r requirements.txtrequirements.txt内容如下requests2.31.03.4 GitHub Token 准备GitHub API 支持匿名访问但匿名请求的速率限制较低批量分析很容易触发限流。建议生成一个 personal access token。生成步骤登录 GitHub。进入 Settings - Developer settings - Personal access tokens。选择生成 Fine-grained token 或 classic token。不需要额外仓库权限因为只读取公开数据选最小权限即可。把生成的 Token 保存好不要直接写在脚本里。运行脚本时通过环境变量注入 Token# Linux / macOS export GITHUB_TOKEN你的token # Windows PowerShell $env:GITHUB_TOKEN你的token3.5 网络访问脚本需要访问https://api.github.com。在运行前可以先测试网络连通性curl -I https://api.github.com如果长时间无法访问需要检查当前网络的出口策略确保能连通 GitHub API。4. 安装部署与启动方式4.1 文件结构建议建一个独立目录结构如下repo-health/ ├── repo_health.py # 主脚本 ├── requirements.txt # 依赖 ├── repos.txt # 仓库列表TXT 格式 └── report.md # 输出报告4.2 仓库列表格式支持两种输入格式。TXT 格式每行一个仓库格式为owner/namepytorch/pytorch tensorflow/tensorflow huggingface/transformersCSV 格式至少包含repo或url字段repo,url pytorch/pytorch,https://github.com/pytorch/pytorch tensorflow/tensorflow,https://github.com/tensorflow/tensorflow脚本会自动识别文件后缀。CSV 文件需要带.csv后缀TXT 文件带.txt后缀。4.3 主脚本代码将以下内容保存为repo_health.pyimport csv import os import sys import time from datetime import datetime import requests API_BASE https://api.github.com def parse_repo(repo_str): repo_str repo_str.strip().strip(/) parts repo_str.split(/) if len(parts) 2: return parts[-2], parts[-1] return None, None def fetch_repo_data(owner, name, token): headers {Accept: application/vnd.githubjson} if token: headers[Authorization] fBearer {token} url f{API_BASE}/repos/{owner}/{name} response requests.get(url, headersheaders, timeout30) response.raise_for_status() return response.json() def fetch_releases(owner, name, token): headers {Accept: application/vnd.githubjson} if token: headers[Authorization] fBearer {token} url f{API_BASE}/repos/{owner}/{name}/releases?per_page5 response requests.get(url, headersheaders, timeout30) response.raise_for_status() return response.json() def fetch_open_issues(owner, name, token): headers {Accept: application/vnd.githubjson} if token: headers[Authorization] fBearer {token} url f{API_BASE}/repos/{owner}/{name}/issues?stateopenper_page1 response requests.get(url, headersheaders, timeout30) response.raise_for_status() return response.json() def analyze_repo(repo_str, token): owner, name parse_repo(repo_str) if not owner or not name: return {repo: repo_str, error: 仓库格式不正确应使用 owner/name} try: data fetch_repo_data(owner, name, token) releases fetch_releases(owner, name, token) issues fetch_open_issues(owner, name, token) pushed_at data.get(pushed_at, ) created_at data.get(created_at, ) updated_at data.get(updated_at, ) stars data.get(stargazers_count, 0) forks data.get(forks_count, 0) open_issues_count data.get(open_issues_count, 0) has_issues data.get(has_issues, True) license_info data.get(license, None) license_name license_info.get(spdx_id, NOASSERTION) if license_info else 无 release_dates [ r.get(published_at) or r.get(created_at) for r in releases if r.get(published_at) or r.get(created_at) ] latest_release_date max(release_dates) if release_dates else None score 0 current_time datetime.utcnow() def age_days(date_str): if not date_str: return None try: dt datetime.strptime(date_str, %Y-%m-%dT%H:%M:%SZ) return (current_time - dt).days except ValueError: return None pushed_days age_days(pushed_at) release_days age_days(latest_release_date) if pushed_days is not None: if pushed_days 30: score 30 elif pushed_days 90: score 20 elif pushed_days 365: score 10 if release_days is not None: if release_days 90: score 30 elif release_days 365: score 15 else: score 5 if stars 10000: score 20 elif stars 1000: score 15 elif stars 100: score 10 else: score 5 if license_name and license_name ! NOASSERTION: score 10 if forks 0: score 5 return { repo: f{owner}/{name}, stars: stars, forks: forks, open_issues_count: open_issues_count if has_issues else disabled, created_at: created_at, pushed_at: pushed_at, updated_at: updated_at, latest_release: latest_release_date, license: license_name, score: score, } except requests.exceptions.HTTPError as e: if e.response.status_code 404: return {repo: f{owner}/{name}, error: 仓库不存在检查是否公开或拼写错误} elif e.response.status_code 403: return {repo: f{owner}/{name}, error: API 限流或 Token 无权限稍后再试} elif e.response.status_code 401: return {repo: f{owner}/{name}, error: Token 无效请检查 GITHUB_TOKEN} else: return {repo: f{owner}/{name}, error: fHTTP {e.response.status_code}} except requests.exceptions.RequestException as e: return {repo: f{owner}/{name}, error: f网络请求失败: {str(e)}} def main(): token os.environ.get(GITHUB_TOKEN, ) if not token: print([提示] 未设置 GITHUB_TOKEN匿名请求限流较严建议先设置环境变量。) if len(sys.argv) 2: print(用法: python repo_health.py 仓库列表文件 [输出报告文件]) return input_file sys.argv[1] output_file sys.argv[2] if len(sys.argv) 2 else report.md repos [] if input_file.endswith(.csv): with open(input_file, newline, encodingutf-8) as f: reader csv.DictReader(f) for row in reader: repo_str (row.get(repo) or row.get(url) or ).strip() if repo_str: repos.append(repo_str) else: with open(input_file, encodingutf-8) as f: repos [line.strip() for line in f if line.strip()] if not repos: print(没有读取到仓库列表请检查输入文件。) return print(f开始分析 {len(repos)} 个仓库...) results [] for i, repo_str in enumerate(repos, 1): print(f[{i}/{len(repos)}] 分析 {repo_str}) results.append(analyze_repo(repo_str, token)) if i len(repos): time.sleep(1) lines [# 仓库活跃度报告, ] lines.append(f- 生成时间{datetime.utcnow().isoformat()}) lines.append(f- 分析仓库数{len(repos)}) lines.append() lines.append(| 仓库 | Stars | Forks | Open Issues | 最近Push | 最近Release | License | 评分 | 备注 |) lines.append(| --- | --- | --- | --- | --- | --- | --- | --- | --- |) for res in results: if error in res: lines.append( f| {res[repo]} | - | - | - | - | - | - | - | {res[error]} | ) else: lines.append( f| {res[repo]} | {res[stars]} | {res[forks]} | f{res[open_issues_count]} | {res[pushed_at] or N/A} | f{res[latest_release] or N/A} | {res[license]} | f{res[score]} | 正常 | ) report \n.join(lines) with open(output_file, w, encodingutf-8) as f: f.write(report) print(f报告已生成{output_file}) if __name__ __main__: main()4.4 启动运行先写一个repos.txtpytorch/pytorch tensorflow/tensorflow huggingface/transformers然后运行python repo_health.py repos.txt report.md启动后可以看到类似输出[提示] 未设置 GITHUB_TOKEN匿名请求限流较严建议先设置环境变量。 开始分析 3 个仓库... [1/3] 分析 pytorch/pytorch [2/3] 分析 tensorflow/tensorflow [3/3] 分析 huggingface/transformers 报告已生成report.md脚本会逐个请求 GitHub API每个仓库之间间隔 1 秒避免触发限流。整个过程不需要 GPU网络延迟和 API 响应速度是主要等待时间。5. 功能测试与效果验证5.1 测试单仓库先只保留一个仓库例如pytorch/pytorch运行后打开report.md重点检查表格中是否有数据。是否有error字段。评分是否正常计算。License、Stars、Forks、Open Issues 是否与 GitHub 页面一致。预期结果报告里会包含该仓库的公开元数据。如果返回 404先检查仓库名是否拼写错误或者仓库是否已经转为私有。判断成功的标准很简单报告生成无异常并且输出文件能正常打开。5.2 测试批量仓库在repos.txt中放入 10 到 20 个仓库再次运行python repo_health.py repos.txt report.md观察两点是否会因为限流导致部分请求失败。是否每个仓库都有输出。如果设置了 Token批量结果会更稳定。匿名请求在连续几个仓库后容易被限流这也是脚本里加入time.sleep(1)的原因。5.3 查看报告字段report.md是一个 Markdown 表格字段含义如下字段含义Stars仓库 Star 数量Forks仓库 Fork 数量Open Issues当前打开状态的 Issue 数量最近Push最后一次 push 到默认分支的时间最近Release最近一次发布 Release 的时间License仓库声明的开源许可证评分基于维护活跃度和社区规模的简单打分评分逻辑在脚本里写得很明确最近 30 天内有 Push加 30 分。最近 90 天内发布过 Release加 30 分。Star 数超过 1 万加 20 分。有明确的 License加 10 分。这个评分是启发式的不代表项目真实质量只用于快速排序和初步筛选。5.4 测试异常输入故意在repos.txt写入错误格式not-a-repo运行脚本应该看到该行返回格式错误其他正常仓库继续分析。脚本不会因为单行错误而中断这也是批量任务的基本要求。6. 接口 API 与批量任务6.1 使用到的 GitHub API脚本主要调用了三个公开接口GET /repos/{owner}/{repo}获取仓库基本信息。GET /repos/{owner}/{repo}/releases获取 Release 列表。GET /repos/{owner}/{repo}/issues?stateopen获取 Open Issue 列表。可以用 curl 直接测试curl -L \ -H Accept: application/vnd.githubjson \ -H Authorization: Bearer YOUR_GITHUB_TOKEN \ https://api.github.com/repos/pytorch/pytorch返回的 JSON 中包含stargazers_count、forks_count、pushed_at、license等字段。如果只需要验证 Token 是否有效可以请求/user接口curl -H Authorization: Bearer YOUR_GITHUB_TOKEN https://api.github.com/user6.2 Python 调用方式在任意 Python 脚本中也可以直接复用脚本里的函数import os import requests owner pytorch name pytorch token os.environ.get(GITHUB_TOKEN, ) headers {Accept: application/vnd.githubjson} if token: headers[Authorization] fBearer {token} url fhttps://api.github.com/repos/{owner}/{name} response requests.get(url, headersheaders, timeout30) print(response.json()[stargazers_count])这样可以把活跃度检查集成到自己的监控系统里。6.3 批量任务设计脚本从输入文件读取仓库列表然后逐个请求。这种线性批量方式足够应对几十个仓库的日常分析。使用时注意每个仓库需要 1 到 2 次 API 请求脚本目前最多请求 3 次。批量规模建议控制在 100 个仓库以内避免长时间运行。每两个仓库之间间隔 1 秒是平衡速度和限流的选择。如果需要处理几百上千个仓库建议增加失败重试和结果缓存。失败重试建议遇到403 rate limit exceeded不要立即重试等待后重跑整个任务。遇到5xx错误可以等 10 秒后重试。遇到404或401不需要重试直接记录错误原因。7. 资源占用与性能观察7.1 CPU 和内存脚本不涉及 AI 推理也没有 Python 之外的重量级依赖。分析一个仓库时内存占用通常只有几十 MBCPU 几乎可以忽略。7.2 网络请求是主要瓶颈每个仓库需要等待 GitHub API 返回 JSON。响应速度取决于当前网络环境和服务端负载。批量分析时总耗时约等于“仓库数 x 单仓库请求耗时 间隔时间”。如果 100 个仓库每个仓库平均 1 秒请求加上 1 秒间隔总耗时大概在 3 到 5 分钟。这个量级适合放在.github/workflows中定时执行。7.3 如何观察资源占用在 Linux / macOS 下可以用time python repo_health.py repos.txt report.md在 Windows PowerShell 下可以用Measure-Command { python repo_health.py repos.txt report.md }观察脚本总耗时以及过程中是否出现 API 限流错误。7.4 减少 API 调用次数当前脚本对每个仓库最多发 3 次请求。如果只要核心活跃度可以减少为只请求 Repo 数据不再请求 Releases 和 Issues。这样速度更快但信息量也会减少。另一个方向是改用 GitHub GraphQL API在单个请求中查询多个仓库的多个字段。GraphQL 的节点限制和配额逻辑与 REST 不同扩展前需要先确认当前配额。8. 常见问题与排查方法问题现象可能原因排查方式解决方案运行后提示ModuleNotFoundError: requests没有安装依赖执行pip install requests使用venv并按requirements.txt安装依赖报告显示仓库格式不正确仓库列表中没有owner/name结构检查输入文件每行内容改成pytorch/pytorch这种格式报告显示仓库不存在仓库名拼写错误或私有化浏览器打开仓库地址确认修正仓库名或使用有权限的 Token报告显示API 限流匿名请求超限或 Token 配额不足查看响应头中的X-RateLimit-Remaining设置GITHUB_TOKEN增大脚本内sleep间隔报告显示Token 无效Token 过期或没有正确注入环境变量检查GITHUB_TOKEN是否为空重新生成 Token确认环境变量已生效提示网络请求失败无法访问api.github.com执行curl -I https://api.github.com排查网络出口策略确认可以访问 GitHub API输出报告为空输入文件为空或格式不对打印读取到的仓库列表检查文件路径和编码UTF-8 编码最稳妥CSV 文件没读取到仓库缺少repo或url列查看 CSV 表头增加repo或url字段批量任务长时间卡住网络超时或某个仓库请求无响应观察日志停在哪一个仓库增加timeout参数已经默认 30 秒报告数字和 GitHub 页面不一致API 数据和网页存在缓存延迟检查 API 返回时间以 API 返回为准必要时稍后重试9. 最佳实践与使用建议9.1 第一次先跑小规模测试先在repos.txt中放 3 个仓库跑通脚本确认输出格式符合预期后再扩大到完整清单。不要一上来就分析几百个仓库避免限流问题干扰判断。9.2 保留最小可运行配置把requirements.txt、repo_health.py、repos.txt放在同一个目录形成一套可复用的最小配置。换机器时只需要重新安装依赖和配置 Token。9.3 不要把 Token 写进脚本脚本从环境变量读取 Token这是一个安全做法。如果使用.env文件也要确保该文件不会被提交到 Git 仓库。可以在.gitignore中加入.env venv/ *.md但要谨慎使用全局通配符避免误删 README 等需要保留的 Markdown 文件。9.4 定时运行并保存历史仓库活跃度是一个随时间变化的数据适合定时采集。推荐放在 GitHub Actions 中每周运行一次并把报告作为构建产物上传。参考工作流配置.github/workflows/repo-health.ymlname: repo-health-report on: schedule: - cron: 0 8 * * 1 workflow_dispatch: jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - uses: actions/setup-pythonv5 with: python-version: 3.11 - run: pip install -r requirements.txt - run: python repo_health.py repos.txt report.md env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - uses: actions/upload-artifactv4 with: name: repo-report path: report.md这样可以直接用 GitHub 自带的 Token不需要额外 secrets每周自动生成一份报告。9.5 结合更多信号做决策活跃度评分只能回答“这个仓库最近有没有人在动”但回答不了“这个项目适不适合我的业务”。在做选型时还要看文档是否完整。Issue 和 Pull Request 的响应质量。Release 变更是否破坏兼容性。社区里是否有真实使用者。License 是否允许当前使用方式。9.6 合规使用数据GitHub API 数据可以用于技术分析和内部评估但不要大规模爬取、转售或用于绕过平台限制。分析结果中的 License 信息只用于筛选不替代法律意见。10. 总结与下一步这个脚本最值得用的点是能把“仓库维护状态”变成一个可批量比较的表格。对于长期维护的项目持续看到 Push 和 Release 更新比短期 Star 暴涨更有参考价值。建议拿到脚本后先验证单仓库效果再扩大到自己的依赖清单。最容易踩的坑是 GitHub API 限流所以一定记得设置 Token并保持请求间隔。后续可以继续扩展的方向把报告发送到钉钉、飞书或企业微信机器人。增加历史数据存储绘制仓库活跃度趋势线。解析仓库的 Release 变更日志自动标记重大版本更新。接入本地依赖清单自动巡检全部上游仓库。开源选型不是追新也不是看谁声音大。数据稳定、维护持续、社区还有人愿意一起玩才是“择机而动、安稳为先”的真正含义。这套脚本可以帮你把那句“我感觉这个项目还活着”变成一份可留档、可对比、可定时更新的报告。
网站建设高端定制企业官网