过去半个月,我几乎每天都会在链上过一遍新合约、新池子和异动交易。很多人看到别人说“抓到了金狗”,第一反应是打听具体地址,但说实话,单纯拿到一个地址意义不大,因为不知道筛选逻辑、不会验证真伪,反而容易变成接盘的人。我更建议把方法沉淀下来:链上筛选、热度验证、风险过滤,然后才是技术层面的自动化扫描。这篇文章我会完整复盘这半个月用到的链上追踪思路,附带一套可运行的 Python 扫描脚本,供对链上数据分析和 Web3 开发感兴趣的读者参考。
先说清楚:本文只讨论链上数据处理与工程技术,不构成任何投资建议,也不存在所谓的“财富密码”。链上代币风险极高,尤其新合约往往伴随貔貅盘、恶意授权和流动性抽走等不确定因素,任何人都要先学会保护自己,再讨论收益。把这层风险意识放在最前面,比记住任何脚本都重要。
1. 背景与核心概念
1.1 什么是“金狗”以及链上追踪的本质
在加密社区里,“金狗”通常指早期市值极低、随后价格大幅上涨的代币。这个词带有不小的运气成分和情绪色彩,但从技术角度看,我们可以把它还原成几个可量化的链上特征:合约创建时间短、持有人快速增长、交易量快速放大、流动性池被添加、链上转账频繁等。
这些数据不是秘密,因为区块链本身就是公开账本。任何地址的转账记录、任何合约的创建时间、任何池子的流动性变化,都可以通过节点或区块浏览器查询到。所谓“链上追踪”,本质就是把分散在区块中的事件日志、交易记录、合约状态抓取下来,再按自己的逻辑过滤和打分。
1.2 为什么链上监控比交易所上币信息更早
一个代币的生命周期通常从链上开始:先有合约部署,然后创建流动性池,出现第一批链上买卖,最后才可能被交易所收录。如果只盯着交易所数据,看到的热门币往往已经经历了早期阶段。
链上事件则不同。流动性池子刚建立、部署者开始转移代币、第一批持有人地址出现,这些事件在交易上链后几秒甚至几毫秒内就能被监控脚本捕捉到。这也是很多开发者研究早期代币时选择链上数据作为主要信号源的原因。链上监控做的是“比别人更早看到状态变化”,而不是预测某个代币会上涨。
1.3 这篇文章适合谁
- 想入门链上数据分析,但不知道从哪下手的开发者。
- 已经会用区块浏览器,但希望用脚本自动扫描和分析数据的工程师。
- 对 Web3.py 感兴趣,想做一个真实链上数据抓取小项目的读者。
- 以及所有想在参与链上代币之前,先学会用数据做基础判断的人。
如果你只是想要一个“必涨清单”,那这篇文章帮不到你;如果你想建立一套可复用的链上筛选与验证框架,下面的内容应该能提供不少思路。
2. 环境准备与工具链
2.1 基础运行环境
本文示例使用 Python 编写,主要依赖 Web3.py 库。版本需要根据你的项目实际情况调整,本文以常见环境为例,重点演示配置思路。
建议环境如下:
操作系统:Windows 10/11、Ubuntu 20.04+、macOS 均可 Python:3.9 及以上 Web3.py:6.x 或 7.x 均可 节点服务:支持以太坊 JSON-RPC 的公共节点或自建节点如果还没有 Python 环境,建议先安装 Anaconda 或直接从 Python 官网下载安装包。创建独立虚拟环境可以避免依赖冲突,这一步在真实项目中很值得做:
python -m venv venv source venv/bin/activate # Windows 下执行 venv\Scripts\activate2.2 数据源与工具清单
做链上追踪不需要太多复杂系统,核心是一个能访问链上数据的 RPC 节点,以及一些用于交叉验证的平台。
| 工具类型 | 常见选择 | 作用 |
|---|---|---|
| RPC 节点 | 公共节点、云节点、自建节点 | 读取区块、交易、合约状态、事件日志 |
| 区块浏览器 | Etherscan 等 | 手动查看合约源码、交易流向、持有人分布 |
| DEX 数据平台 | DexScreener、GeckoTerminal 等 | 查看代币价格、流动性池、交易对变化 |
| 数据分析平台 | Dune 等 | 编写 SQL 做历史数据分析和统计 |
| 自定义脚本 | Web3.py / ethers.js | 自动抓取链上数据并按规则过滤 |
RPC 节点是整个链路的地基。公共节点方便,但并发请求容易触发限流;自建节点数据完整,但需要同步成本。对于小范围扫描,先用公共节点跑通逻辑,后续再考虑多节点负载均衡。
2.3 工程目录结构
本文实战案例会创建一个最小化项目,目录结构如下:
golddog_scanner/ ├── .env # 存放 RPC 地址等敏感配置 ├── requirements.txt # Python 依赖 └── scanner.py # 扫描脚本真实项目中还需要加入日志模块、数据库存储、告警通知等,但先跑通最小闭环是更务实的第一步。
3. 我常用的五个链上初筛信号
3.1 新合约与新增流动性池
新合约是最基础的信号。一个地址在链上第一次创建合约,意味着新的项目出现了。但新合约太多,真正关键的是合约是否创建了流动性池。
流动性池可以理解为代币是否具备了“可交易”的基础条件。没有池子的代币,合约再新也无法在 DEX 上买卖。所以“新合约 + 新池子”组合出现的瞬间,往往是监控价值最高的节点。
3.2 持有人数量裂变
持有人数量是判断早期热度的重要指标。如果部署者把代币一次性转移给上百个地址,且这些地址之间没有明显的批量创建规律,可能意味着项目方在做空投或市场分发。反过来,如果持有人列表里大量地址来自同一个创建者,可能存在“刷量”嫌疑。
在链上识别持有人分布并不难:解析 Transfer 事件,统计每个目标地址的余额变化。更复杂的是判断这些地址是否独立,这需要聚类分析,比如查看这些地址是否在同一笔交易中被批量转账。
3.3 交易量快速放大
交易量是另一个有效信号。一个新合约如果长时间没有交易,说明市场关注度极低;如果突然在某个区块高度前后出现密集交易,大概率是有资金进场或者有社区开始关注。
但交易量也可能被刷出来。通过自买自卖制造繁荣假象,是很多风险项目的常规操作。因此交易量需要与持有人分散度、池子深度一起看,不能单看一个指标。
3.4 合约所有权与安全权限
合约代码是否开源、是否存在 owner 权限、owner 能否增发代币或修改交易费率,这些都是基础风控点。很多新合约通过隐藏函数实现黑名单、暂停转账、增发等能力,普通用户很难从交易记录中直接察觉。
用代码层面可以做部分探测:读取合约代码、确认是否开源、调用常见敏感函数接口。更完善的做法是把合约字节码提交给安全审计工具分析,但这已经超出“抓数据”的范畴,属于安全审计领域。
3.5 链上数据与社区信息交叉验证
链上数据可以告诉我们“发生了什么”,但很难告诉我们“为什么发生”。这时候需要结合项目官网、官方社群、代码仓库等信息做交叉验证。
我半个月来的体感是:链上信号负责发现,社区信息负责排雷。一个完全没有任何公开资料的代币,链上数据再漂亮,风险也可能极高。交叉验证不是让你去追热点,而是帮你过滤掉明显不合理的信号。
4. 完整实战:用 Python 扫描新合约
下面进入核心部分,用 Web3.py 实现一个最简单的链上扫描器,完成以下流程:
获取最新区块号 -> 遍历区块内交易 -> 找到创建合约的交易 -> 获取合约地址 -> 读取代币名称和符号 -> 输出结果这个脚本虽然简单,但已经覆盖了链上数据抓取的核心链路,你可以在此基础上扩展出池子监控、持有人统计和告警通知。
4.1 创建项目结构
先创建项目目录和虚拟环境:
mkdir golddog_scanner cd golddog_scanner python -m venv venv source venv/bin/activate # Windows 下执行 venv\Scripts\activate接着创建requirements.txt:
web3>=6.0.0 python-dotenv>=1.0.0 requests>=2.31.0安装依赖:
pip install -r requirements.txt4.2 配置 RPC 地址
创建.env文件,填入可用的 RPC 地址。示例中不写死具体服务商,你需要根据自己使用的节点服务来填写:
RPC_URL=https://your-rpc-endpoint BLOCK_RANGE=20BLOCK_RANGE表示每次扫描多少区块。区块范围越大,扫描时间越长,也越容易触发 RPC 限流,建议先用小范围测试。
4.3 编写扫描脚本
创建scanner.py,完整代码如下:
import os import sys import time from datetime import datetime, timezone from dotenv import load_dotenv from web3 import Web3 load_dotenv() RPC_URL = os.getenv("RPC_URL") BLOCK_RANGE = int(os.getenv("BLOCK_RANGE", "20")) w3 = Web3(Web3.HTTPProvider(RPC_URL)) # 最小 ERC20 接口,只需读取常用的元数据 TOKEN_ABI = [ { "constant": True, "inputs": [], "name": "name", "outputs": [{"name": "", "type": "string"}], "type": "function", }, { "constant": True, "inputs": [], "name": "symbol", "outputs": [{"name": "", "type": "string"}], "type": "function", }, { "constant": True, "inputs": [], "name": "decimals", "outputs": [{"name": "", "type": "uint8"}], "type": "function", }, ] def get_token_meta(address: str): """尝试读取代币名称、符号和小数位数,失败返回 None""" try: contract = w3.eth.contract( address=Web3.to_checksum_address(address), abi=TOKEN_ABI ) name = contract.functions.name().call() symbol = contract.functions.symbol().call() decimals = contract.functions.decimals().call() return name, symbol, decimals except Exception: return None def scan_block(block_number: int): """扫描单个区块,找出所有新创建的合约地址并返回代币信息""" block = w3.eth.get_block(block_number, full_transactions=True) hits = [] for tx in block.transactions: # 创建合约的交易,to 字段为 None if tx.get("to") is not None: continue try: receipt = w3.eth.get_transaction_receipt(tx["hash"]) except Exception: continue contract_address = receipt.get("contractAddress") if not contract_address: continue meta = get_token_meta(contract_address) if meta is None: continue ts = datetime.fromtimestamp( block["timestamp"], tz=timezone.utc ).strftime("%Y-%m-%d %H:%M:%S") hits.append({ "block": block_number, "tx_hash": tx["hash"].hex(), "deployer": tx["from"], "contract": contract_address, "name": meta[0], "symbol": meta[1], "decimals": meta[2], "time": ts, }) return hits def main(): if not w3.is_connected(): print("RPC 连接失败,请检查 .env 中的 RPC_URL") sys.exit(1) latest = w3.eth.block_number start = latest - BLOCK_RANGE + 1 print(f"当前区块: {latest},扫描范围: {start} ~ {latest}") total = 0 for number in range(start, latest + 1): try: hits = scan_block(number) except Exception as err: print(f"区块 {number} 扫描异常: {err}") continue for hit in hits: total += 1 print("=" * 60) print(f"时间: {hit['time']}") print(f"代币名称: {hit['name']} ({hit['symbol']})") print(f"合约地址: {hit['contract']}") print(f"部署地址: {hit['deployer']}") print(f"所在区块: {hit['block']}") print(f"交易哈希: {hit['tx_hash']}") time.sleep(0.2) print(f"\n扫描完成,共发现 {total} 个可读取元数据的新合约。") if __name__ == "__main__": main()这段脚本的完整逻辑是:先连接 RPC,遍历指定区块范围内的每一笔交易,筛选出“to 字段为空”的合约创建交易,然后通过 receipt 拿到合约地址,最后尝试读取代币名称、符号和小数位数。如果一个合约连这三个基础方法都不可读,通常说明它不符合标准 ERC20 结构,需要额外注意。
4.4 运行与预期输出
在.env中配置好 RPC 后运行:
python scanner.py预期输出类似:
当前区块: 20123456,扫描范围: 20123437 ~ 20123456 ============================================================ 时间: 2025-01-15 08:32:11 代币名称: Test Token (TT) 合约地址: 0x1234... 部署地址: 0xabcd... 所在区块: 20123440 交易哈希: 0xdeadbeef... ============================================================ ... 扫描完成,共发现 3 个可读取元数据的新合约。注意:公共 RPC 节点对大量eth_getBlockByNumber和eth_getTransactionReceipt请求非常敏感,很容易出现超时或 429 限流。如果遇到这种情况,可以调小BLOCK_RANGE,或者在每次请求之间加更长的 sleep 时间。
4.5 把脚本扩展为持续监控
实际使用中,手动运行一次脚本意义有限,我们通常希望它持续轮询新区块。可以加一层while True循环,每隔一段时间扫描一次最新区块:
def loop_forever(interval: int = 30): last_block = w3.eth.block_number while True: latest = w3.eth.block_number if latest > last_block: for number in range(last_block + 1, latest + 1): hits = scan_block(number) for hit in hits: # 这里可以接数据库、钉钉/飞书机器人、Telegram Bot 等 print("发现新合约:", hit) last_block = latest time.sleep(interval)这个版本会在每次新出块后自动扫描,真正做到“链上事件驱动”。你可以把输出部分替换为写入数据库或发送告警通知。
5. 进阶:从“发现”到“交叉验证”
扫描到新合约只是第一步,能不能从潜在目标中过滤出更值得关注的信号,取决于后续验证。以下是我在半个月里反复使用的几个验证维度。
5.1 解析 Transfer 事件,统计持有人增长
代币持有人数量可以用 Transfer 事件的接收地址集合近似估算。思路如下:从合约部署区块开始解析 Transfer 事件,记录所有to地址,去重后得到近似持有人数量。如果某个新合约在短时间内出现几十甚至上百个不同接收地址,说明分发正在发生。
下面是一个读取 Transfer 事件数量的核心片段:
TRANSFER_EVENT_ABI = { "anonymous": False, "inputs": [ {"indexed": True, "name": "from", "type": "address"}, {"indexed": True, "name": "to", "type": "address"}, {"indexed": False, "name": "value", "type": "uint256"}, ], "name": "Transfer", "type": "event", } def count_transfer_events(token_address: str, from_block: int, to_block: int = None): if to_block is None: to_block = w3.eth.block_number contract = w3.eth.contract( address=Web3.to_checksum_address(token_address), abi=[TRANSFER_EVENT_ABI] ) logs = contract.events.Transfer().get_logs( from_block=from_block, to_block=to_block ) return len(logs)通过get_logs可以拿到指定范围内的全部事件。如果需要统计持有人的完整地址集合,只需要遍历 logs 里的args.to并放入 set 即可。
5.2 检查部署者与初始转账
部署者地址是新合约最关键的关联方。通过查看部署者的历史交易,可以判断这个地址是否属于批量部署工具,或者是同一个项目方连续部署过多份合约。
建议把部署者地址在区块浏览器中打开,重点看三件事:
- 部署了多少个合约。
- 代币创建后是否立即转出了大部分 supply。
- 部署者地址是否与池子创建地址高度重合。
如果同一个部署者在一个月内创建了大量内容相似的代币合约,这属于典型的批量生产模式,应当格外警惕。
5.3 高权重验证清单
我这里整理了一份日常使用的检查清单,不一定完整,但很实用:
| 验证项 | 关注点 |
|---|---|
| 合约是否开源 | 不开源的合约风险显著提高 |
| 是否存在 owner/管理员地址 | 有权限地址需要重点监控 |
| 是否创建了流动性池 | 没有池子就没有实际交易渠道 |
| 池子创建后是否立即移除流动性 | 属于高风险行为 |
| 持有人拓扑是否过于集中 | 前 10 名持有比例过高是风险信号 |
| 是否有公开社区和代码仓库 | 完全匿名且无公开资料需谨慎 |
| 代码是否有隐藏增发/黑名单函数 | 需要专业工具进一步审计 |
把这套清单做成自动化的评分系统,就是个人链上筛选框架的雏形。每个指标赋一个权重,最后生成综合评分,可以有效减少情绪化决策。
6. 常见问题与排查思路
这半个月里,我也遇到了不少工程上的坑,最常见的有下面几类。
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| RPC 连接失败 | 节点地址错误、网络不可达、服务商限制 | 检查 .env 配置,换一个稳定节点测试 |
| 请求频繁被限流 | 公共节点对并发量有限制 | 降低扫描频率,增加 sleep,或使用私有节点 |
| 扫描区块速度很慢 | 每个区块一笔笔获取 receipt,串行请求太多 | 缩小 BLOCK_RANGE,使用异步 Web3 或批量请求 |
| 合约元数据读不出来 | 合约不是标准 ERC20,或调用方法名不匹配 | 不要硬读,记录地址后转人工分析 |
| 事件日志解析失败 | ABI 与链上事件签名不一致 | 确认事件定义、indexed 字段和 topic 对应关系 |
| 时区显示混乱 | 区块时间戳是 Unix 时间戳,直接本地格式化导致偏差 | 统一用 UTC 时间并在展示层转换 |
如果你也想做链上监控,我的建议是:先跑通最小脚本,再叠加信号;先学会控制回撤,再谈寻找机会。链上数据的迷人之处在于每个地址都留下了痕迹,但能不能从中读出有效信息,取决于你的数据工程能力。
7. 最佳实践与工程建议
7.1 基础设施层面
不要把所有请求都打到一个公共节点。更好的做法是维护一个 RPC 节点池,在请求失败时自动切换。另一方面,扫描程序不能只存在内存里,需要把关键数据落库,比如使用 SQLite 或 PostgreSQL 保存每次扫描到的合约地址和事件日志,方便回溯分析。
另外,告警推送要设计成可配置的。最开始可以只打印日志,跑通后再接入钉钉、飞书或 Telegram Bot,避免在开发阶段被通知轰炸。
7.2 数据处理层面
链上原始数据非常“脏”。新合约可能伪造 name 和 symbol,Transfer 事件里的 value 也可能因为 decimals 不同而误导判断。建议所有数据统一转换为标准单位后再做比较。同时保留原始值,方便排查问题。
解析合约时要注意异常处理。一个恶意合约可能在name()调用中抛异常,甚至故意返回超大字符串阻塞你的脚本。所有外部调用都应该包 try-except,并设置合理的超时时间。
7.3 安全与风险控制
这是最重要的一条。脚本中永远不要保存私钥或助记词,任何需要签名的操作都要单独放在隔离环境里。使用第三方节点时,不要在请求参数中带敏感信息;如果后续做监控机器人,机器人只负责“观察和提醒”,不要负责“自动下单”,更不要碰链上资产。
从风险控制角度看,链上代币天然存在极高不确定性。即使所有链上信号都正常,也不能保证项目不会跑路。一定要把仓位控制在自己能接受的损失范围内,并且充分理解“本金归零”的可能性。
8. 总结与下一步
这半个月的链上追踪经历让我意识到,真正重要的不是抓到某个具体代币,而是沉淀出一套稳定的数据流水线:扫描合约、解析事件、统计持有人、交叉验证、记录结果。把这些环节自动化之后,每天只需要花很少时间查看异常信号即可。
如果你也想做链上监控,我的建议是:先跑通最小脚本,再叠加信号;先学会控制回撤,再谈寻找机会。链上数据的迷人之处在于每个地址都留下了痕迹,但能不能从中读出有效信息,取决于你的数据工程能力。下一步可以继续研究事件日志过滤、LP 池子监控、持有人聚类分析,以及把多个链上的数据统一接入同一套监控体系。先从一个简单的 Python 脚本开始,把流程跑顺,再逐步扩展成真正属于自己的链上数据监控系统。