Python与以太坊交互实战:Web3.py库的使用指南
引言
以太坊作为最流行的智能合约平台之一,为开发者提供了构建去中心化应用(DApps)的强大能力。Web3.py是Python生态系统中与以太坊交互的核心库,它封装了JSON-RPC接口,提供了简洁易用的API用于连接节点、发送交易、部署和调用智能合约等操作。本文将带你从零开始,全面掌握Web3.py的使用方法。
1. 环境准备与基础配置
1.1 安装Web3.py
首先需要安装Web3.py库及其相关依赖:
# 安装Web3.py核心库
pip install web3
# 安装Solidity编译器(用于编译智能合约)
pip install py-solc-x
# 安装Infura SDK(可选,用于便捷连接Infura节点)
pip install infura-sdk1.2 连接以太坊节点
要与以太坊网络交互,必须连接到一个以太坊节点。常见的选择包括:
- 本地节点(如Geth、Nethermind、Erigon)
- 第三方节点服务(如Infura、Alchemy、QuickNode)
以下是使用Infura连接以太坊主网的示例:
from web3 import Web3
# Infura项目ID(需注册获取)
INFURA_PROJECT_ID = "your-project-id-here"
# 连接以太坊主网
infura_url = f"https://mainnet.infura.io/v3/{INFURA_PROJECT_ID}"
web3 = Web3(Web3.HTTPProvider(infura_url))
# 验证连接状态
if web3.is_connected():
print("✅ 已成功连接到以太坊主网")
else:
print("❌ 连接失败")1.3 网络配置
不同的以太坊网络有不同的配置参数:
| 网络 | Chain ID | 测试网 faucet |
|---|---|---|
| 主网 | 1 | - |
| Goerli测试网 | 5 | https://goerlifaucet.com/ |
| Sepolia测试网 | 11155111 | https://www.infura.io/faucet/sepolia |
连接测试网示例:
# 连接Sepolia测试网
sepolia_url = f"https://sepolia.infura.io/v3/{INFURA_PROJECT_ID}"
web3_sepolia = Web3(Web3.HTTPProvider(sepolia_url))
print(f"Sepolia网络连接状态:{web3_sepolia.is_connected()}")2. 核心区块链操作
2.1 获取区块链基础信息
# 获取当前块号
block_number = web3.eth.block_number
print(f"当前块号:{block_number}")
# 获取最新块详细信息
latest_block = web3.eth.get_block("latest")
print(f"最新块哈希:{latest_block.hash.hex()}")
print(f"块包含交易数:{len(latest_block.transactions)}")
print(f"块时间戳:{latest_block.timestamp}")
# 获取指定块信息
block_10000000 = web3.eth.get_block(10000000)
print(f"第10000000块矿工:{block_10000000.miner}")2.2 账户与地址操作
# 创建新账户
new_account = web3.eth.account.create()
print(f"新账户地址:{new_account.address}")
print(f"新账户私钥:{new_account.key.hex()}")
# 从私钥加载账户
private_key = "0xYourPrivateKeyHere"
account = web3.eth.account.from_key(private_key)
print(f"加载的账户地址:{account.address}")
# 验证地址格式
address = "0xEthereumAddressHere"
is_valid = web3.is_address(address)
print(f"地址格式是否有效:{is_valid}")
# 转换为校验和地址
checksum_address = web3.to_checksum_address(address)
print(f"校验和地址:{checksum_address}")2.3 ETH余额查询
# 查询账户余额
address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" # Vitalik Buterin地址
balance_wei = web3.eth.get_balance(address)
balance_eth = web3.from_wei(balance_wei, "ether")
print(f"账户余额:{balance_eth} ETH")3. 交易操作
3.1 构建并发送ETH交易
# 定义发送者、接收者和私钥
sender_address = "0xSenderAddressHere"
receiver_address = "0xReceiverAddressHere"
private_key = "0xSenderPrivateKeyHere"
# 获取当前gas价格
gas_price = web3.eth.gas_price
print(f"当前gas价格:{web3.from_wei(gas_price, 'gwei')} Gwei")
# 获取发送者的nonce(交易次数)
nonce = web3.eth.get_transaction_count(sender_address)
# 构建交易对象
transaction = {
"to": receiver_address,
"value": web3.to_wei(0.01, "ether"), # 发送0.01 ETH
"gas": 21000, # 普通ETH转账的固定gas限制
"gasPrice": gas_price,
"nonce": nonce,
"chainId": 1 # 主网Chain ID
}
# 签名交易
signed_transaction = web3.eth.account.sign_transaction(transaction, private_key)
print(f"已签名交易:{signed_transaction}")
# 发送交易
tx_hash = web3.eth.send_raw_transaction(signed_transaction.rawTransaction)
print(f"交易哈希:{web3.to_hex(tx_hash)}")
# 等待交易确认
tx_receipt = web3.eth.wait_for_transaction_receipt(tx_hash)
print(f"交易确认状态:{'成功' if tx_receipt.status == 1 else '失败'}")
print(f"交易包含在块:{tx_receipt.blockNumber}")3.2 交易状态查询
# 根据哈希查询交易
tx_hash = "0xTransactionHashHere"
transaction = web3.eth.get_transaction(tx_hash)
print(f"交易发送者:{transaction['from']}")
print(f"交易接收者:{transaction['to']}")
print(f"交易价值:{web3.from_wei(transaction['value'], 'ether')} ETH")
print(f"交易gas价格:{web3.from_wei(transaction['gasPrice'], 'gwei')} Gwei")4. 智能合约交互
4.1 编译智能合约
from solcx import compile_source, install_solc
# 安装指定版本的Solidity编译器
install_solc("0.8.20")
# 智能合约源代码
contract_source = """
pragma solidity ^0.8.20;
contract SimpleStorage {
uint256 private _value;
event ValueStored(uint256 value);
event ValueUpdated(uint256 oldValue, uint256 newValue);
function store(uint256 value) public {
_value = value;
emit ValueStored(value);
}
function update(uint256 newValue) public {
uint256 oldValue = _value;
_value = newValue;
emit ValueUpdated(oldValue, newValue);
}
function retrieve() public view returns (uint256) {
return _value;
}
}
"""
# 编译合约
compiled_contract = compile_source(contract_source, output_values=["abi", "bin"])
contract_interface = compiled_contract["<stdin>:SimpleStorage"]
print(f"合约ABI:{contract_interface['abi']}")
print(f"合约字节码:{contract_interface['bin']}")4.2 部署智能合约
# 构建合约实例
SimpleStorage = web3.eth.contract(abi=contract_interface["abi"], bytecode=contract_interface["bin"])
# 构建部署交易
deploy_transaction = SimpleStorage.constructor().build_transaction(
{
"from": sender_address,
"nonce": nonce,
"gas": 1000000, # 部署合约需要更多gas
"gasPrice": gas_price,
"chainId": 1
}
)
# 签名并发送部署交易
signed_deploy = web3.eth.account.sign_transaction(deploy_transaction, private_key)
deploy_tx_hash = web3.eth.send_raw_transaction(signed_deploy.rawTransaction)
# 等待部署完成
deploy_receipt = web3.eth.wait_for_transaction_receipt(deploy_tx_hash)
print(f"✅ 合约部署成功!")
print(f"合约地址:{deploy_receipt.contractAddress}")
print(f"部署交易哈希:{deploy_receipt.transactionHash.hex()}")4.3 调用智能合约方法
# 加载合约实例
contract_address = deploy_receipt.contractAddress
simple_storage = web3.eth.contract(address=contract_address, abi=contract_interface["abi"])
# 调用view/pure方法(无需交易,免费)
current_value = simple_storage.functions.retrieve().call()
print(f"合约当前存储值:{current_value}")
# 发送交易调用write方法
new_value = 42
update_transaction = simple_storage.functions.update(new_value).build_transaction(
{
"from": sender_address,
"nonce": web3.eth.get_transaction_count(sender_address),
"gas": 500000,
"gasPrice": gas_price,
"chainId": 1
}
)
signed_update = web3.eth.account.sign_transaction(update_transaction, private_key)
update_tx_hash = web3.eth.send_raw_transaction(signed_update.rawTransaction)
web3.eth.wait_for_transaction_receipt(update_tx_hash)
# 再次读取值
updated_value = simple_storage.functions.retrieve().call()
print(f"合约更新后存储值:{updated_value}")4.4 监听智能合约事件
# 创建事件过滤器(从最新块开始)
event_filter = simple_storage.events.ValueUpdated.create_filter(fromBlock="latest")
# 获取新事件
new_events = event_filter.get_new_entries()
for event in new_events:
print(f"📅 事件类型:{event.event}")
print(f" 旧值:{event.args.oldValue}")
print(f" 新值:{event.args.newValue}")
print(f" 交易哈希:{event.transactionHash.hex()}")
# 获取历史事件
history_events = simple_storage.events.ValueUpdated.get_logs(fromBlock=deploy_receipt.blockNumber)
print(f"历史事件总数:{len(history_events)}")5. 高级功能与最佳实践
5.1 WebSocket实时监听
# 使用WebSocket连接
infura_ws_url = f"wss://mainnet.infura.io/ws/v3/{INFURA_PROJECT_ID}"
web3_ws = Web3(Web3.WebsocketProvider(infura_ws_url))
# 订阅新块事件
def handle_new_block(block_hash):
block = web3_ws.eth.get_block(block_hash)
print(f"🚀 新块:{block.number},包含交易:{len(block.transactions)}")
# 开始监听
web3_ws.eth.subscribe("newHeads", handle_new_block)
# 保持连接
import time
while True:
time.sleep(1)5.2 Gas优化
# 估算交易gas
estimated_gas = web3.eth.estimate_gas(transaction)
print(f"估算gas:{estimated_gas}")
# 使用EIP-1559交易(伦敦硬分叉后)
from web3.gas_strategies.time_based import fast_gas_price_strategy
# 设置gas策略
web3.eth.set_gas_price_strategy(fast_gas_price_strategy)
# 构建EIP-1559交易
transaction_eip1559 = {
"to": receiver_address,
"value": web3.to_wei(0.01, "ether"),
"gas": 21000,
"maxPriorityFeePerGas": web3.to_wei(2, "gwei"), # 矿工小费
"maxFeePerGas": web3.to_wei(50, "gwei"), # 最大gas费
"nonce": nonce,
"chainId": 1
}5.3 错误处理
try:
tx_hash = web3.eth.send_raw_transaction(signed_transaction.rawTransaction)
tx_receipt = web3.eth.wait_for_transaction_receipt(tx_hash)
except ValueError as e:
print(f"交易失败:{e}")
except Exception as e:
print(f"发生未知错误:{e}")6. 常见问题与解决方案
6.1 连接失败
- 检查网络连接和节点URL是否正确
- 确保Infura项目ID有效
- 对于本地节点,确保节点正在运行
6.2 交易失败
- Out of gas:增加gas限制或检查交易是否有错误
- Nonce too low:nonce值必须连续且唯一
- Insufficient funds:确保账户有足够的ETH支付交易费用
- Invalid address:确保地址格式正确(使用校验和地址)
6.3 合约交互错误
- 确保ABI和合约地址正确
- 检查函数参数类型和数量是否匹配
- 确保合约已成功部署并确认
总结
Web3.py是Python开发者与以太坊交互的强大工具,支持从基础的ETH转账到复杂的智能合约开发。通过本文的学习,你应该已经掌握了Web3.py的核心功能和使用方法。
要深入了解Web3.py,可以参考:
- 官方文档:https://web3py.readthedocs.io/
- 以太坊开发文档:https://ethereum.org/zh/developers/docs/
- Web3.py GitHub仓库:https://github.com/ethereum/web3.py
现在,你可以开始构建自己的以太坊应用了!🚀
(此内容由 AI 辅助生成,仅供参考)