3. 数据采集入门:使用Python调用RPC节点获取区块数据(Web3.py基础)
好,咱们正式开始动手了。
前面两章聊了聊链上数据的价值,也画了画筹码分布的理论框架。但说一千道一万,数据从哪来?
这一章,我就带你亲手把数据从链上“拽”下来。
说白了,我们要干的事就一件:让Python跟以太坊节点对话,把区块、交易、日志这些原始数据拿到本地。
3.1 为什么是Web3.py?
你可能会问:市面上那么多工具,为什么非要用Web3.py?
我个人习惯是:能用Python解决的,绝不用别的。Web3.py是Python生态里最成熟的以太坊交互库,没有之一。它封装了JSON-RPC协议,你不需要自己拼HTTP请求、解析十六进制返回值——这些脏活累活,库都帮你干了。
我在项目中遇到过好几次,团队里有人用curl直接调RPC接口,结果被各种数据格式转换搞得焦头烂额。后来换成Web3.py,代码量直接砍掉一半。
3.2 环境准备:装好你的工具箱
嗯,这里要注意:Python版本最好3.8以上。我建议你新建一个虚拟环境,别把全局环境搞乱了。
# 创建虚拟环境(我习惯用venv)
python -m venv web3_env
source web3_env/bin/activate # Mac/Linux
# web3_env\Scripts\activate # Windows
# 安装Web3.py
pip install web3
# 验证安装
python -c "from web3 import Web3; print(Web3.__version__)"
看到版本号输出,说明装好了。
3.3 连接节点:你的链上入口
有了Web3.py,下一步就是连节点。节点分两种:
- 自建节点:自己跑Geth或Nethermind,数据全、无限制,但维护成本高
- 第三方节点:Infura、Alchemy、QuickNode这些服务商,开箱即用
我个人建议:刚开始用Infura就够了。免费套餐每天10万次请求,做课程实验绰绰有余。
from web3 import Web3
# 连接Infura节点(记得换成你自己的API Key)
infura_url = "https://mainnet.infura.io/v3/YOUR_API_KEY"
w3 = Web3(Web3.HTTPProvider(infura_url))
# 检查是否连接成功
if w3.is_connected():
print("✅ 连接成功!当前区块高度:", w3.eth.block_number)
else:
print("❌ 连接失败,检查网络或API Key")
你想想看,就这么几行代码,你已经跟以太坊主网连上了。是不是挺简单的?
.env文件,用python-dotenv加载。
3.4 获取区块数据:从最新区块开始
连接成功,咱们来抓点真东西。
# 获取最新区块
latest_block = w3.eth.get_block('latest')
print("区块号:", latest_block['number'])
print("时间戳:", latest_block['timestamp'])
print("交易数量:", len(latest_block['transactions']))
# 获取指定区块(比如第18000000号区块)
block = w3.eth.get_block(18000000, full_transactions=True)
print("区块哈希:", block['hash'].hex())
print("矿工地址:", block['miner'])
print("Gas使用量:", block['gasUsed'])
这里有个坑,我踩过:get_block的第二个参数full_transactions,默认是False。如果设为True,它会返回完整的交易对象,而不是交易哈希列表。数据量会大很多,请求也慢一些。
我曾经在分析某个DeFi项目时,一口气拉了1000个区块的完整交易数据,结果等了快10分钟。后来学乖了:先拿哈希列表,需要时再按需拉取具体交易。
3.5 解析交易数据:读懂链上每一笔操作
区块拿到了,交易也拿到了。但这些十六进制数据到底什么意思?
咱们来拆解一笔典型的以太坊转账交易:
# 获取最新区块的第一笔交易
block = w3.eth.get_block('latest')
tx_hash = block['transactions'][0] # 注意:这里返回的是哈希,不是完整交易
tx = w3.eth.get_transaction(tx_hash)
print("交易哈希:", tx['hash'].hex())
print("发送方:", tx['from'])
print("接收方:", tx['to'])
print("转账金额(ETH):", w3.from_wei(tx['value'], 'ether'))
print("Gas价格(Gwei):", w3.from_wei(tx['gasPrice'], 'gwei'))
print("Nonce:", tx['nonce'])
print("输入数据:", tx['input'][:66] + "...") # 截取前66个字符
你看,from和to就是转账双方地址,value是金额(单位是Wei,我用from_wei转成了ETH)。input字段比较特殊——如果是普通转账,它通常是0x;如果是合约调用,里面就藏着函数签名和参数。
3.6 获取交易收据:确认交易状态
光有交易还不够,你还得知道这笔交易到底执行成功了没有。这时候就需要交易收据(Transaction Receipt)。
# 获取交易收据
receipt = w3.eth.get_transaction_receipt(tx_hash)
print("区块号:", receipt['blockNumber'])
print("Gas实际消耗:", receipt['gasUsed'])
print("状态:", "成功 ✅" if receipt['status'] == 1 else "失败 ❌")
print("日志数量:", len(receipt['logs']))
status字段是1还是0,直接告诉你这笔交易有没有回滚。我在做链上监控时,第一件事就是过滤掉status=0的交易——那些失败的交易,数据没有分析价值。
3.7 实战:批量抓取最近10个区块
理论讲完了,咱们来点实战。下面这段代码,会抓取最近10个区块的概要信息:
from web3 import Web3
from datetime import datetime
w3 = Web3(Web3.HTTPProvider("https://mainnet.infura.io/v3/YOUR_API_KEY"))
current_block = w3.eth.block_number
print(f"当前区块高度:{current_block}")
print("-" * 60)
for i in range(10):
block_num = current_block - i
block = w3.eth.get_block(block_num)
# 时间戳转人类可读格式
timestamp = datetime.fromtimestamp(block['timestamp'])
print(f"区块 #{block_num}")
print(f" 时间:{timestamp}")
print(f" 交易数:{len(block['transactions'])}")
print(f" Gas使用率:{block['gasUsed'] / block['gasLimit'] * 100:.1f}%")
print()
这段代码我经常用来做“链上温度计”——如果Gas使用率持续高于90%,说明网络很拥堵,这时候做交易要小心了。
3.8 避坑指南:我踩过的那些坑
最后,分享几个我实战中遇到的坑:
- 请求频率限制:Infura免费版每秒最多5次请求。我曾经写了个循环抓1000个区块,结果直接被封了10分钟。解决方案:加
time.sleep(0.3),或者用Alchemy(免费版每秒330次请求)。 - 数据格式:Web3.py返回的哈希值都是
HexBytes类型,不能直接当字符串用。记得调用.hex()方法转换。 - 大区块处理:有些区块包含上千笔交易,一次性拉取完整数据会非常慢。我建议先拉取交易哈希列表,再分批处理。
- 节点同步延迟:你查到的“最新区块”可能比实际链上慢几秒。做实时监控时,记得留出6-12个区块的确认时间。
3.9 本章知识体系
下面这张图,帮你理清本章的核心逻辑:
这张图把整个数据采集流程串起来了。从环境准备到连接节点,再到获取区块、交易、收据,最后解析存储——每一步都是下一章分析的基础。
好了,这一章的内容就到这。代码不多,但都是实打实能跑的东西。你最好打开编辑器,跟着敲一遍。光看是学不会的,动手才是硬道理。