拆解Orbit区块链交易调查工具核心代码:ranker排行算法、getNew去重与pageLimit分页机制详解
【免费下载链接】OrbitBlockchain Transactions Investigation Tool项目地址: https://gitcode.com/gh_mirrors/orbit5/Orbit
Orbit 是一款开源的区块链交易调查工具(Blockchain Transactions Investigation Tool),它能从一个比特币钱包地址出发,递归爬取交易历史,并将资金往来渲染成可视化图谱,帮你快速锁定可疑的来源、去向和关联地址。本文将带你读懂 Orbit 三个最核心的实现机制:pageLimit分页计算、rankerTop-N 排行筛选和getNew去重逻辑,看看这个不到 150 行的主程序是如何组织起一场完整的链上调查的 🔍
一、先认识 Orbit:它能做什么?
Orbit 的工作方式可以概括为一句话:给一个种子地址,它自动"滚雪球"式地挖出整个交易网络。
以某个地址为起点,Orbit 会抓取它最近 50 笔(默认)交易,找出所有交互过的地址;再对这批新地址重复同样的过程,一层一层向下挖掘(默认 3 层)。最终所有地址和连接被整理成图谱,在浏览器中展示——节点越大、边越粗,代表交易越频繁。
对于安全研究员、反欺诈分析师或区块链爱好者来说,这是一个轻量的链上追踪工具:无需部署节点,一条命令即可开始调查。
克隆仓库并运行
Orbit 要求 Python 3.2 及以上版本,克隆后即可使用:
git clone https://gitcode.com/gh_mirrors/orbit5/Orbit cd Orbit python3 orbit.py -s 1AJbsFZ64EpEfS5UAjAfcUG8pH8Jn3rn1F💡 多个种子地址用逗号分隔即可,例如
-s addr1,addr2。
二、项目结构总览:核心文件清单
Orbit 的结构非常精简,所有逻辑都集中在一个入口文件加 7 个核心模块中:
| 文件 | 职责 |
|---|---|
orbit.py | 程序入口:参数解析、爬取主循环、图谱组装 |
core/utils.py | 本文主角:pageLimit、ranker、getNew、genLocation |
core/getTransactions.py | 单地址交易抓取,按页循环请求接口 |
core/requester.py | 封装 blockchain.info 的rawaddr接口请求 |
core/prepareGraph.py | 把 JSON 数据注入 Quark 的quark.html完成可视化 |
core/exporter.py | 导出graphml或原始json文件 |
core/getQuark.py | 首次运行时自动下载 Quark 图查看器 |
core/colors.py | 终端 ANSI 彩色输出 |
理解了这张地图,我们就能进入core/utils.py的三个"机关"了。
三、pageLimit 分页机制:如何算出要请求几页?
区块链数据接口每次最多返回50 条交易记录。用户通过-l参数指定"最多抓取多少笔交易"(默认 100),Orbit 需要把"条数"换算成"页数"——这就是pageLimit的工作。
它由两个函数配合完成:
def pageLimit(n): return int((round(n, 49)/49) + 1) def round(n, m): r = n % m return n + m - r if r + r >= m else n - r1. 自定义 round:就近取整到 49 的倍数
这里的round是作者自己实现的"就近取整":把n舍入到距离它最近的m(这里是 49)的倍数。
round(100, 49):100 距 98 更近(差 2),返回98round(50, 49):50 距 49 更近(差 1),返回49
2. pageLimit:除以 49 再 +1,多要一页兜底
公式round(n, 49) / 49 + 1拆开看:先算需要几个"49 条"的整块,再额外加一页作为缓冲——因为接口最后一页往往不满 50 条,多请求一次能保证实际抓到的记录数不缩水。
举几个具体例子感受一下:
-l参数 | round 取整后 | 页数 = 取整值÷49 + 1 |
|---|---|---|
| 50 | 49 | 49÷49 + 1 =2 页 |
| 100 | 98 | 98÷49 + 1 =3 页 |
| 147 | 147 | 147÷49 + 1 =4 页 |
| 200 | 196 | 196÷49 + 1 =5 页 |
3. getTransactions 中的分页循环
core/getTransactions.py拿到页数后逐页请求,并把交易对端地址累加进database:
pages = pageLimit(limit) for i in range(pages): if pages > 1 and increment != 0: trail = '?offset=%i' % increment response = requester(address) ... increment += 50🔎一个值得玩味的细节:拼好的trail = '?offset=...'偏移量变量,实际上并没有拼进最终的请求 URL(core/requester.py只拼接了地址本身)。也就是说,多页循环目前拿到的是同一批记录。分页的"骨架"已经搭好——只差一次字符串拼接。也正因为如此,后面的ranker和getNew才成为保证结果质量的关键。阅读开源代码时,这类"差一步"的实现细节正是最值得观察的地方。
四、ranker 排行算法:Top N 地址是如何筛出来的?
爬取一层下来,某个地址可能关联了几十个对端地址。但不是所有关系都值得继续深挖——Orbit 用ranker为每个节点只保留交易次数最多的前 N 个地址(对应-t参数,默认 20),把"弱连接"剪掉,控制图谱的爆炸式增长。
它的核心思路不是排序,而是追踪 Top 数组中的最小值:
def ranker(database, top): newDatabase = {} for node in database: newDatabase[node] = {} topSize = [0 for i in range(top)] # 大小槽位 topAdd = ['' for i in range(top)] # 地址槽位 for each in database[node]: minimum = min(topSize) if database[node][each] > minimum: index = topSize.index(minimum) topSize[index] = database[node][each] topAdd[index] = each for size, address in zip(topSize, topAdd): newDatabase[node][address] = size return newDatabase用生活化的比喻:想象一排 N 个座位(初始都是空的),每来一位"交易次数更多"的嘉宾,就挤掉当前坐着的分数最低那位。遍历结束后,留在座位上的就是 Top N。
这里有三个设计细节值得注意:
database的数据结构:{节点地址: {对端地址: 交易次数}}。次数在抓取阶段由core/getTransactions.py里的database[address][found] += 1累加而来——每多一笔共同交易,计数加 1。- 空槽位是"故意的":当某节点的对端数量少于
top时,剩余槽位保持0和空字符串''。别担心,这些占位符会被下一站的getNew清理掉。 top + 1的小心思:主循环orbit.py中每层调用的是ranker(database, top + 1),即每层多留一个名额,给下一层的扩展留出余量;爬完最后一层后才用ranker(database, top)收敛到精确的 Top N 再输出。
五、getNew 去重机制:processed 集合如何避免重复爬取
深度爬取最大的风险是重复劳动:同一个地址可能被几十个邻居同时发现。Orbit 用一个全局的processed集合(orbit.py中初始化的set())记录"已经爬过的地址",getNew负责挑出还没爬过的新面孔:
def getNew(database, processed): new = [] for address in database: if address not in processed: new.append(address) for childAddress in database[address]: if childAddress not in processed: new.append(childAddress) return set(filter(None, new))三段逻辑,各司其职:
- 节点本身 + 子节点都检查:不只是看新邻居,连当前节点自身若还没爬过也会被纳入,保证不遗漏;
set(...)去重:同一地址可能被多个邻居反复"推荐",集合自动去重;filter(None, ...)清障:顺手把ranker留下的空字符串占位符过滤掉——两个函数之间一个精巧的"接力"🧩。
processed则在core/getTransactions.py中、每个地址抓取完成时被processed.add(address)写入,形成"先认领、后放行"的闭环。
六、三者协同:一轮完整爬取的数据流
把三个机制串起来,orbit.py主循环的每一步都各司其职:
| 步骤 | 调用 | 作用 |
|---|---|---|
| ① 剪枝 | ranker(database, top + 1) | 每个节点只保留交易最频繁的 Top N 对端 |
| ② 去重 | getNew(database, processed) | 挑出未爬取过的新地址,返回集合 |
| ③ 抓取 | crawl(...)线程池并发(10 线程) | 每个地址按pageLimit分页拉取交易 |
| ④ 记录 | processed.add(address) | 已爬地址入册,供下一层去重 |
整个循环重复depth次(默认 3 层)。最后orbit.py将database转成节点/边 JSON,交给core/prepareGraph.py注入quark.html,浏览器中就能看到资金网络的完整图谱;如果带了-o参数,core/exporter.py还会导出graphml或json供后续分析。
七、快速上手:常用参数一览
| 参数 | 作用 | 默认值 |
|---|---|---|
-s | 种子地址(多个用逗号分隔) | 必填 |
-d | 爬取深度(向下挖掘的层数) | 3 |
-t | 每层保留的 Top N 地址数(ranker 生效) | 20 |
-l | 每个地址最多抓取交易数(pageLimit 生效) | 100 |
-o | 导出文件(.graphml/.json) | 无 |
一条典型的"深度调查"命令:
python3 orbit.py -s 1AJbsFZ64EpEfS5UAjAfcUG8pH8Jn3rn1F -l 100 -d 3 -t 20 -o result.graphml运行完成后,quark.html会自动在浏览器打开。如果图谱看起来一团乱麻,可以在 Quark 中依次点击Make Clusters → Color Clusters → Spacify,用社区发现算法把可疑簇"聚"出来,一目了然 📊
八、小结
Orbit 虽然代码量不大,却是一个麻雀虽小五脏俱全的爬虫工程范本:
pageLimit用"就近取整 + 多要一页"的朴素算术解决条数到页数的换算,分页骨架清晰;ranker用最小值追踪代替排序,实现低开销的 Top N 剪枝,有效控制图谱规模;getNew用set+processed集合完成去重闭环,顺手清理上游的占位符。
如果你想深入理解区块链交易调查工具的实现,不妨从core/utils.py这三个函数读起——它们正是 Orbit 从"一堆地址"到"一张图谱"的核心引擎。
【免费下载链接】OrbitBlockchain Transactions Investigation Tool项目地址: https://gitcode.com/gh_mirrors/orbit5/Orbit
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考