# gitlab_spider **Repository Path**: eleven-power/gitlab_spider ## Basic Information - **Project Name**: gitlab_spider - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-22 - **Last Updated**: 2026-08-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # GitLab 公开仓库数据采集系统 从 gitlab.com 采集 >=390 万公开仓库的 4 类数据:元信息+源码包、MR、Issue、项目文档。 ## 项目结构 ``` ├── pipeline.py # 主采集入口(ProcessPoolExecutor 多进程并行) ├── collector_v2.py # 核心采集模块 ├── benchmark.py # 采集速率监控(每分钟统计各状态数量) ├── config.py # 配置 + TokenPool(跨进程共享、随机分配、自动轮换) ├── tokens.json # GitLab API Token 列表 ├── start.sh # Linux 交互启动脚本 ├── start.ps1 # Windows PowerShell 交互启动脚本 ├── docker-compose.yml # MongoDB Docker 部署 ├── requirements.txt # Python 依赖 ├── scripts/ # 辅助脚本 │ ├── retry.py # 下载失败补采工具 │ ├── stats.py # 采集统计(ID 范围、状态分布、发现进度、中位数) │ ├── export_half_pending.py # 导出未采集仓库(按 ID 升序取尾部指定数量) │ ├── export_closed.py # 导出 closed 状态仓库 │ └── import_pending.py # 导入 JSON 文件到 MongoDB └── meta/ # 数据清洗与合并 ├── merge_docs_issue_mr.py # 合并多服务器 docs/issue/mr 分片文件 ├── merge_meta.py # 合并多服务器元数据(100MB 分片) ├── merge_meta_single.py # 合并多服务器元数据(单文件) └── clean_meta.py # 元数据清洗(字段/重复/zip缺失/壳仓库) ``` ## 环境准备 ```bash pip install uv # 安装 uv uv sync # 安装依赖 docker compose up -d # 启动 MongoDB(或使用系统安装的 mongod) git --version # 确保 Git 已安装 ``` ## Token 配置 将所有 GitLab Personal Access Token 放入 **tokens.json**: ```json [ "glpat-xxxxxxxxxxxx", "glpat-yyyyyyyyyyyy" ] ``` 也支持环境变量: ```bash export GITLAB_TOKENS="token1,token2,..." export GITLAB_TOKEN_FILE="/path/to/tokens.json" ``` **TokenPool 机制:** | 特性 | 说明 | |------|------| | 随机分配 | 每个工作进程启动时从池中随机取一个 token | | 自动轮换 | 401(失效)或持续 429(用尽)→ 标记 + 换另一个 | | 跨进程共享 | 一个进程标记失效,其他进程通过 Manager 立即感知 | ## 启动采集 ### 交互菜单(推荐) **Linux:** `./start.sh` **Windows:** 右键 `start.ps1` → "使用 PowerShell 运行"(首次需 `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned`) 菜单功能: | 菜单 | 功能 | |------|------| | 1 | 启动 discover(多线程发现仓库) | | 2 | 查看 discover 日志(实时) | | 3 | 启动采集(多进程并行) | | 4 | 查看采集日志(实时) | | 5 | 启动补采(重试 download_failed) | | 6 | 查看速率监控(实时) | | 7 | 修改输出目录(持久化到 .env) | | 8 | 修改进程数(持久化到 .env) | | 9 | 生成 JSONL 元数据 | | 10 | 查看所有日志 | | 11 | 查看进程状态 + 磁盘空间 | | 12 | 停止 discover | | 13 | 停止采集/补采 | | 0 | 退出 | 环境变量预设: ```bash OUTPUT_DIR=/mnt/data WORKERS=16 ./start.sh ``` ### 命令行 ```bash # 发现仓库 uv run python pipeline.py --output /data/gitlab --discover # 采集 uv run python pipeline.py --output /data/gitlab --workers 16 --max-repos 1000 # 查看进度 uv run python pipeline.py --output /data/gitlab --status # 导出元数据 JSONL uv run python pipeline.py --output /data/gitlab --export ``` ### 参数说明 | 参数 | 默认值 | 说明 | |------|--------|------| | `--output` / `-o` | `gitlab_repo` | 输出目录 | | `--workers` / `-w` | CPU×4 | 工作进程数 | | `--max-repos` / `-n` | 0(无限制) | 最多采集多少个 | | `--discover` | - | 仓库发现模式 | | `--export` | - | 导出元数据 JSONL | | `--status` | - | 查看 checkpoint 统计 | | `--reset-claims` | - | 清除过期认领(崩溃恢复) | | `--reset-fallback` | - | 下载失败 → pending | | `--fix-orphans` | - | 修复文件缺失的 completed 记录 | ### 内置保护 | 机制 | 说明 | |------|------| | 磁盘空间 | 剩余 < 2GB 自动进入休眠等待,空间恢复后继续 | | 仓库大小 | git clone 过程实时检测 > 100MB 自动 kill | | 内存保护 | git `PACK_SIZE_LIMIT=512m` 等限制,防 OOM | | 壳仓库跳过 | clone 后检测只有 README/文档 → 标记 dead | | 优雅退出 | Ctrl+C → 1 秒内中止 clone → 保存断点 → 退出 | ### 多机分片部署 每台机器配不同的 `PROJECT_ID` 区间: ```bash # 机器1: [0, 8500000) export PROJECT_ID_MIN=0 PROJECT_ID_MAX=8500000 uv run python pipeline.py --output /data/gitlab --discover uv run python pipeline.py --output /data/gitlab # 机器2: [8500000, 17000000) export PROJECT_ID_MIN=8500000 PROJECT_ID_MAX=17000000 ... ``` ## 监控与统计 ### 速率监控 ```bash uv run python benchmark.py ``` 每分钟输出所有状态的数量和增量: ``` 10:30:01 pending:114500(-500) completed:5000(+500) failed:500(+0) dead:0(+0) ``` ### 采集统计 ```bash uv run python scripts/stats.py ``` ``` 仓库总数: 582225 ID范围: 450 ~ 64654625 已采集: 47255 未采集: 524661 下载失败: 10309 永久失败: 0 发现完成: 否 进度: 725457/85000000 (0.853%) 未采集ID中位数: 21272909 超出配置范围: 0 (区间 [0, 85000000)) ``` ## 补采下载失败 ```bash # 查看失败数量 uv run python scripts/retry.py --output /data/gitlab --status # 补采全部失败 uv run python scripts/retry.py --output /data/gitlab # 补采指定数量 uv run python scripts/retry.py --output /data/gitlab --max-repos 50 ``` ## 多机迁移 ### 导出未采集仓库 从源服务器导出 pending 仓库,状态改为 closed: ```bash uv run python scripts/export_half_pending.py # 全部 uv run python scripts/export_half_pending.py 50000 # 后 5 万条 uv run python scripts/export_half_pending.py 10w # 后 10 万条 ``` ### 导出 closed 仓库 ```bash uv run python scripts/export_closed.py # 全部 uv run python scripts/export_closed.py 5w # 后 5 万条 ``` ### 导入到目标服务器 ```bash uv run python scripts/import_pending.py # 默认 export_pending.json uv run python scripts/import_pending.py a.json b.json # 多个文件 uv run python scripts/import_pending.py scripts/export_*.json # glob 匹配 ``` ## 数据清洗与交付 ### 合并多服务器分片(docs/issue/mr) ```bash uv run python meta/merge_docs_issue_mr.py \ --src /srv1/data --src /srv2/data --src /srv3/data \ --dst /delivery/data ``` 按 `track_id` 去重,100MB 分片,输出干净文件名 `mr_202607_part001.jsonl`。 ### 合并多服务器元数据 ```bash # 分片版(100MB/片) uv run python meta/merge_meta.py \ --src /srv1/data --src /srv2/data \ --dst /delivery/meta # 单文件版 uv run python meta/merge_meta_single.py \ --src /srv1/data --src /srv2/data \ --dst /delivery/meta ``` 输出格式:`gitlab_repo_meta_{数量}_{日期}.jsonl` ### 元数据清洗 ```bash uv run python meta/clean_meta.py \ --meta /delivery/meta/gitlab_repo_meta_3900000_260802.jsonl \ --zip-dir /data/gitlab/main_file \ --dst /delivery/cleaned ``` 支持多个元数据文件: ```bash uv run python meta/clean_meta.py \ --meta /delivery/meta/gitlab_repo_meta_3900000_260802_part*.jsonl \ --zip-dir /data/gitlab/main_file \ --dst /delivery/cleaned ``` 清洗规则(按顺序): | 规则 | 不合格输出 | |------|-----------| | 14 个必填字段缺失 | `gitlab_repo_meta_missing_fields_{n}_{date}.jsonl` | | project_id 重复 | `gitlab_repo_meta_duplicate_{n}_{date}.jsonl` | | zip 文件缺失 | `gitlab_repo_meta_missing_zip_{n}_{date}.jsonl` | | 壳仓库(≤50KB 且无代码) | `gitlab_repo_meta_shell_repo_{n}_{date}.jsonl` | | ✓ 合格 | `gitlab_repo_meta_valid_{n}_{date}.jsonl` | ## 维护命令 ```bash # 清除过期认领(进程崩溃后恢复) uv run python pipeline.py --output /data/gitlab --reset-claims # 重置下载失败为 pending uv run python pipeline.py --output /data/gitlab --reset-fallback # 修复文件缺失的 completed 记录(手动) uv run python pipeline.py --output /data/gitlab --fix-orphans # 停止所有进程 kill -INT $(pgrep -f pipeline.py) ``` ## MongoDB 常用命令 ```javascript // 状态统计 db.repo_status.aggregate([{$group: {_id: "$status", count: {$sum: 1}}}]); // dead → download_failed(重新补采) db.repo_status.updateMany({status: "dead"}, {$set: {status: "download_failed", retry_count: 0}}); // 全部重置为 pending(慎用) db.repo_status.updateMany({}, {$set: {status: "pending", retry_count: 0}}); // 按 track_id 恢复被 _fix_orphans 误伤的 db.repo_status.updateMany({status: "pending", track_id: {$exists: true}}, {$set: {status: "completed"}}); ``` ## 输出目录结构 ``` /data/gitlab/ ├── gitlab_repo_meta_41379_260801.jsonl # 元数据(导出时生成) ├── main_file/ # 源码 zip 包 │ └── 20260721_14/ # 按小时分目录 │ └── owner__repo__hash.zip ├── merge_request/ # MR 数据(按月分片,_p{pid} 多进程后缀) │ └── mr_202607_part001_p12345.jsonl ├── issue/ # Issue 数据 │ └── issue_202607_part001_p12345.jsonl └── docs/ # 项目文档 ├── readme_202607_part001_p12345.jsonl ├── wiki_202607_part001_p12345.jsonl └── changelog_202607_part001_p12345.jsonl ``` ## 数据字段(元信息 14 个必填字段) | 字段 | 必填 | 说明 | |------|:--:|------| | track_id | 是 | 全局唯一 ID | | repo_url | 是 | 仓库主页 URL | | repo_full_name | 是 | owner/repo | | platform | 是 | 固定 gitlab | | default_branch | 是 | 默认分支 | | branch_count | 是 | 分支总数(git for-each-ref 本地统计) | | commit_count | 是 | 提交总数(git rev-list 本地统计) | | star_count | 是 | Star 数 | | size_bytes | 是 | 源码包字节数 | | collected_at | 是 | 采集时间 ISO 8601 | | repo_updated_at | 是 | 仓库最后更新时间 | | zip_sha256 | 是 | zip 包 SHA256 | | file_path | 是 | zip 相对路径 | | has_ci | 是 | 是否有 .gitlab-ci.yml | ## 状态说明 | status | 含义 | 补采是否认领 | |--------|------|:--:| | pending | 已发现,待采集 | - | | completed | 全部完成 | - | | download_failed | 下载失败,待补采 | 是 | | dead | 永久跳过(壳仓库/重试超限) | 否 | | closed | 已导出到其他服务器 | 否 |