以太坊作为全球领先的智能合约平台,其区块链数据蕴含巨大价值。本文将详细介绍如何使用 Node.js 构建一个高效的数据爬虫,捕获以太坊主网上的钱包地址、余额及交易信息,并存储至本地数据库。这一方法可用于构建自定义区块链浏览器或进行链上数据分析。
技术栈与核心工具
本项目基于以下关键技术组件:
- Node.js:后端 JavaScript 运行时,用于编写爬虫脚本
- MongoDB:非关系型数据库,存储获取的区块链数据
- Mongoose:MongoDB 对象建模工具,简化数据库操作
- Web3.js:与以太坊区块链交互的 JavaScript 库
- PM2:Node.js 应用进程管理器,保证脚本稳定运行
实现原理与流程设计
主要目标
系统的主要目标是获取以太坊网络上所有活跃钱包地址的余额与交易数量,并将这些数据保存至本地数据库。通过自建数据平台,用户可以摆脱对第三方区块链浏览器的依赖,实现数据的自主控制与深度分析。
核心步骤
- 连接以太坊网络:通过 Infura 提供的 API 端点(或本地部署的 Geth 节点)接入以太坊主网
- 遍历区块链数据:使用
web3.eth.getBlock方法按顺序获取每个区块的信息 - 提取交易数据:对每个区块中的交易记录(transactions)进行解析,获取参与交易的地址信息
- 收集钱包地址:从每笔交易的发送方(from)和接收方(to)字段提取所有唯一地址
- 查询余额信息:使用
web3.eth.getBalance方法获取每个地址的实时余额数据
环境配置与代码实现
前期准备
在开始之前,请确保系统已安装以下软件:
- Node.js 运行环境
- MongoDB 数据库
- 注册 Infura 账户并创建项目,获取 API 密钥
安装必要的 Node.js 依赖包:
npm install web3 mongoose
核心代码结构
应用主程序 (app.js)
主程序负责连接区块链网络、处理区块数据和管理数据库操作:
// 引入所需模块
const Web3 = require('web3');
const mongoose = require('mongoose');
const AccountModel = require('./accountmodel.js');
// 初始化 Web3 实例
const infuraEndpoint = 'https://mainnet.infura.io/v3/<YOUR_INFURA_PROJECT_ID>';
const web3 = new Web3(new Web3.providers.HttpProvider(infuraEndpoint));
// 工具函数:将 Wei 转换为 Ether
function toEth(weiValue) {
if(typeof weiValue === 'number') return (weiValue / (10**18)).toFixed(8);
}
// 数据库操作函数
async function addNewAccount(address) {
// 检查地址是否已存在,不存在则保存
}
async function checkBlock(blockNumber) {
// 检查区块是否已处理
}
async function updateBlock(blockNumber) {
// 更新已处理的最新区块号
}
// 主循环:遍历区块并提取数据
async function processBlocks() {
const startBlock = 0;
const endBlock = 10000;
for(let blockNumber = startBlock; blockNumber < endBlock; blockNumber++) {
// 检查区块是否已处理
const canProcess = await checkBlock(blockNumber);
if (!canProcess) continue;
// 获取区块数据
const block = await web3.eth.getBlock(blockNumber, true);
if (block && block.transactions.length > 0) {
// 处理区块中的每笔交易
for (const txHash of block.transactions) {
const transaction = await web3.eth.getTransaction(txHash);
// 保存发送方和接收方地址
await addNewAccount(transaction.from);
await addNewAccount(transaction.to);
}
}
// 更新已处理区块记录
await updateBlock(blockNumber);
}
}
// 获取地址余额函数
async function updateBalances() {
// 从数据库获取所有地址
const accounts = await AccountModel.find({ address: { $exists: true } });
for (const account of accounts) {
const balance = await web3.eth.getBalance(account.address);
const etherBalance = toEth(Number(balance));
// 更新数据库中的余额信息
await AccountModel.updateOne(
{ address: account.address },
{ balance: etherBalance }
);
}
}
// 执行主函数
processBlocks().then(() => {
console.log('区块处理完成');
updateBalances();
});
数据模型定义 (accountmodel.js)
定义 MongoDB 中的数据结构和连接:
const mongoose = require('mongoose');
// 连接 MongoDB 数据库
mongoose.connect('mongodb://127.0.0.1:27017/eth_accounts', {
useNewUrlParser: true,
useUnifiedTopology: true
});
// 定义账户模式
const AccountSchema = new mongoose.Schema({
number: Number,
address: String,
balance: String,
txs: Number,
block: Number
});
// 创建并导出模型
const AccountModel = mongoose.model('Account', AccountSchema);
module.exports = AccountModel;
运行与维护
完成代码编写后,按照以下步骤启动系统:
- 启动 MongoDB 服务
- 使用 PM2 启动应用以确保稳定运行:
pm2 start app.js - 监控运行日志,确保数据正确获取和保存
优化建议与注意事项
- 性能优化:对于大量数据的处理,可以考虑使用批量数据库操作和并发请求控制
- 错误处理:增加完善的错误处理和重试机制,提高系统稳定性
- 速率限制:注意 Infura 等服务的 API 调用频率限制,适当添加延迟
- 数据验证:定期验证数据的完整性和准确性,建立数据校验机制
- 增量更新:设计合理的增量更新策略,只处理新产生的区块数据
常见问题
为什么要自建区块链数据爬虫?
自建爬虫可以让您完全控制数据获取过程,避免第三方平台的限制和费率问题。同时,您可以自定义数据结构和存储方式,满足特定分析需求。
如何处理以太坊的高吞吐量?
对于高速链上数据处理,建议采用分布式架构和负载均衡策略。可以考虑将任务拆分为多个子进程,同时处理不同范围的区块数据。
Infura 有什么使用限制?
Infura 免费版有每日请求限额和速率限制。对于大规模数据采集,建议使用多个 API 密钥轮询请求,或考虑搭建本地以太坊节点。
如何确保数据的准确性?
通过多重校验机制确保数据准确,包括对比多个数据源、验证哈希值以及实施数据一致性检查。定期与公共区块链浏览器进行数据比对。
这个系统可以获取哪些类型的数据?
除了基本余额和交易信息,还可以扩展获取智能合约代码、内部交易、代币转移等高级数据,只需相应地扩展 Web3.js 的功能调用。
数据采集过程中断怎么办?
系统设计了断点续传机制,通过记录已处理的区块高度,可以在中断后从最后处理的区块继续采集,避免数据丢失或重复。
通过本文介绍的方法,您可以构建一个强大的以太坊数据采集系统,为区块链分析和应用开发提供可靠的数据支持。