如何通过Etherscan API批量获取Gas耗尽的以太坊合约源码?代码卡顿
问题分析与解决方法
现有代码的问题(为什么卡住无输出)
- 缩进错误:
fetch_contract_source_code函数末尾的with open代码块缩进错误,被包含在函数内部,导致主程序逻辑完全没执行,这是代码无输出的核心原因。 - API接口用错:你调用的
getLogs接口是用来获取合约事件日志的,不包含交易的status、gas、gasUsed字段,根本无法筛选因Gas耗尽失败的交易。 - 遍历逻辑不合理:从块0开始遍历到最新块,数据量极大,免费API速率限制(5次/秒)会导致请求频繁被限制,甚至直接卡住。
- 判断条件无效:日志条目里没有你用来判断的
status和gas/gasUsed字段,这个判断逻辑永远不会触发。
修复后的代码实现
下面是修正后的代码,改用正确的API接口获取交易数据,筛选Gas耗尽的失败交易,并获取对应合约源码:
import time import requests # Etherscan API密钥 API_KEY = "XXXXXXXXXXXXX" BASE_URL = "https://api.etherscan.io/api" def make_api_request(params): """处理API请求,自动处理速率限制""" while True: response = requests.get(BASE_URL, params=params) data = response.json() if data.get("status") == "0": error_msg = data.get("result", "未知错误") print(f"API错误: {error_msg}") if "rate limit" in error_msg.lower(): print("触发速率限制,等待2秒后重试...") time.sleep(2) continue else: return None return data def fetch_contract_source(contract_addr): """获取合约源码""" params = { "module": "contract", "action": "getsourcecode", "address": contract_addr, "apikey": API_KEY } data = make_api_request(params) if data and data["result"]: return data["result"][0]["SourceCode"] return "合约源码不可用" def fetch_failed_gas_exhaust_tx(start_block, end_block): """获取指定块范围内因Gas耗尽失败的交易""" params = { "module": "account", "action": "txlist", "startblock": start_block, "endblock": end_block, "sort": "asc", "apikey": API_KEY } data = make_api_request(params) if not data: return [] # 筛选:交易失败(status=0)且gasUsed等于gas(Gas耗尽) gas_exhaust_tx = [] for tx in data["result"]: if tx["status"] == "0" and tx["gasUsed"] == tx["gas"]: gas_exhaust_tx.append(tx) return gas_exhaust_tx if __name__ == "__main__": # 不要从块0开始,选最近的块范围,比如最近1000个块 start_block = 18000000 end_block = 18001000 output_file = "gas_exhaust_failed_tx.txt" with open(output_file, "w", encoding="utf-8") as f: current_block = start_block step = 100 # 每次查询100个块,避免单次请求数据过大 while current_block <= end_block: batch_end = min(current_block + step - 1, end_block) print(f"正在查询块 {current_block} 到 {batch_end}...") tx_list = fetch_failed_gas_exhaust_tx(current_block, batch_end) if not tx_list: current_block = batch_end + 1 time.sleep(0.2) # 控制请求速率,避免触发限制 continue for tx in tx_list: tx_hash = tx["hash"] contract_addr = tx["to"] # 交易调用的合约地址 f.write(f"交易哈希: {tx_hash}\n") f.write(f"合约地址: {contract_addr}\n") if contract_addr: source_code = fetch_contract_source(contract_addr) f.write(f"合约源码:\n{source_code}\n") f.write("="*50 + "\n") current_block = batch_end + 1 time.sleep(0.2) # 控制请求间隔 print(f"数据已保存到 {output_file}")
其他获取数据的方法
- 链上数据分析平台:使用支持以太坊数据查询的分析工具,通过编写类SQL语句直接筛选"交易失败且gasUsed=gas"的记录,能快速批量获取数据,无需自己写代码遍历。
- 运行本地以太坊节点:同步全节点后,通过节点的JSON-RPC接口直接查询交易数据,不受第三方API的速率限制,但需要足够的存储空间和带宽。
- 付费API服务:使用专业Web3 API服务,它们的速率限制远高于免费版Etherscan API,能支持更大范围的数据查询,适合获取数千条以上的记录。
内容的提问来源于stack exchange,提问作者Maryam Massoud
相关产品推荐
相关产品推荐

