CoinGecko 在一个平台上追踪数千种加密货币,其行情页面包含驱动价格追踪、投资组合工具和研究所需的结构化数据:代币名称和符号、当前价格、市值、24小时交易量、24小时和7天价格变化以及市值排名。对于关注一篮子代币的用户,这些公开行情数据是原始素材,而在数百行之间手动复制数据既耗时又会在您刚完成时就已过期。
本指南向您展示如何用 Python 从 CoinGecko 提取加密货币数据。CoinGecko 发布了官方公开 API,对于任何生产工作负载,这应该是您首先考虑的路径。这里的 HTML 爬取方式是一种教学性备选方案,适用于免费 API 层不覆盖的字段或页面,且完全限定在公开行情数据范围内, 这些是事实性数据而非个人数据。文末有一个真正的合法性说明;在大规模爬取前请务必阅读。
您将构建的内容
一个 Python 脚本,通过 Crawling API 获取渲染后的 CoinGecko 行情页面,用 BeautifulSoup 解析每一行代币,并为每种代币生成一条结构化记录。运行示例以 CoinGecko 主代币列表的顶部代币为准,我们提取以下字段:
- 名称:完整的币名,如 Bitcoin 或 Ethereum。
- 符号:简短的代币符号,如 BTC 或 ETH。
- 价格:您所选法币的当前价格。
- 市值:该代币的总市值。
- 交易量:过去 24 小时的交易量。
- 24小时涨跌幅:过去 24 小时的价格变化百分比。
- 7天涨跌幅:过去 7 天的价格变化百分比。
- 排名:该行显示的市值排名。
为什么普通请求在 CoinGecko 上会失败
用裸 HTTP 客户端请求 CoinGecko 行情页面,通常会得到状态码 200 但正文中只有部分表格数据。两个因素对您不利。首先,CoinGecko 通过 JavaScript 在浏览器中为其行情表格的大部分内容补充数据:价格和百分比变化实时更新,部分行只有在页面脚本运行后才会填充。解析第一个响应,您可能只得到一个不完整的表格,而非完整的行集合。其次,与任何高流量网站一样,CoinGecko 会监测自动流量,而以紧密循环请求的数据中心 IP 会在到达渲染内容之前被限速或挑战。
因此,一个可用的爬虫需要在单次请求中实现两件事:真正渲染页面的浏览器,以及网站视为真实访客的 IP。您可以自己组合无头浏览器和轮换住宅代理池,但将它们组合并保持运行正常才是大部分工作。Crawling API 将两者整合进一次调用:您发送带 JavaScript token 的 URL,它在可信 IP 后渲染页面,并为您返回可解析的完整 HTML。
CoinGecko 提供免费的公开 API,已经以干净的 JSON 格式返回名称、符号、价格、市值、交易量、排名和百分比变化。对于生产用途,请使用它:这是经过授权的路径,完全避免了解析 HTML。仅在 API 层不公开的页面专属字段或视图时才使用 HTML 爬取,且无论哪种方式都请遵守 CoinGecko 的速率限制。
前提条件
在编写代码之前,您需要准备几样东西,都不会花太长时间。
基础 Python 知识。您应当能够编写和运行 Python 脚本,并使用 pip 安装包。如果您不熟悉解析部分,BeautifulSoup 指南是本教程的好伴侣。
Python 3.8 或更高版本。使用 python --version 确认版本。如果尚未安装,请从 python.org 或通过 Anaconda 等发行版安装,并确保 Python 在您的 PATH 中。
Crawlbase 账户和 JS token。注册后,打开控制台,从账户文档页面复制 JavaScript(JS)token。Crawlbase 提供 1,000 次免费请求,足够完成本指南。请像对待密码一样保管 token,勿将其纳入版本控制。
搭建项目
创建虚拟环境以隔离项目依赖,然后安装爬虫所需的库。
python --version python -m venv coingecko_env source coingecko_env/bin/activate pip install crawlbase beautifulsoup4
在 Windows 上,请使用 coingecko_env\Scripts\activate 代替 source 命令。两个依赖项各司其职:crawlbase 是 Crawling API 的官方客户端,beautifulsoup4 解析返回的 HTML 以便按 CSS 选择器提取各字段。json 和 csv 均为标准库,导出步骤无需额外安装。
步骤一:获取渲染后的 CoinGecko 页面
首先获取完整页面。导入 CrawlingAPI 类,用您的 JS token 初始化,并请求 CoinGecko 代币 URL。CoinGecko 在客户端部分更新其表格,因此传入 ajax_wait 和 page_wait 以等待动态内容加载完毕再捕获页面。在解析之前检查 Crawlbase 的 pc_status,可以让失败清晰呈现而非被静默忽略。
from crawlbase import CrawlingAPI api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"}) OPTIONS = { "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/122.0", "ajax_wait": "true", "page_wait": 5000, } def crawl(page_url): response = api.get(page_url, OPTIONS) if response["headers"]["pc_status"] == "200": return response["body"].decode("utf-8") print(f"Request failed: {response['headers']['pc_status']}") return None if __name__ == "__main__": coins_url = "https://www.coingecko.com/" html = crawl(coins_url) print(html[:500] if html else "No HTML returned")
两个等待选项对于部分客户端渲染的目标至关重要。ajax_wait 告知 API 等待异步内容加载完成,page_wait 则在加载后额外等待固定毫秒数,以便延迟渲染的单元格在页面被捕获前出现。五秒是合理的起点;如果行数据返回稀少,可适当延长。运行 python coingecko_scraper.py,您应该看到真实的 CoinGecko 行情标记,而非占位内容。这表示在编写任何选择器之前渲染已正常工作。
CoinGecko 需要在可信 IP 后获取渲染页面,通过一次调用完成,这正是上面的 ajax_wait 和 page_wait 选项所设置的。Crawling API 接受 JS token,在真实浏览器中运行页面,在服务器端轮换住宅 IP,并为您返回完整 HTML,让您无需自行运行无头集群和代理池。先在免费套餐上指向公开行情页面进行测试。
步骤二:解析代币行
CoinGecko 代币页面是一个表格,每行对应一种代币。将渲染后的 HTML 加载到 BeautifulSoup 中,选择表格正文各行,然后通过数据属性读取每个单元格。CoinGecko 使用 data-coin-table-target 值标记其行情单元格,使得按字段而非脆弱的列位置进行定位成为可能。
from bs4 import BeautifulSoup def text_of(row, selector): el = row.select_one(selector) return el.get_text(strip=True) if el else None def parse_coins(html): soup = BeautifulSoup(html, "html.parser") rows = soup.select("table tbody tr") coins = [] for row in rows: name = text_of(row, '[data-coin-table-target="coinName"]') if not name: continue coins.append({ "rank": text_of(row, "td:nth-child(2)"), "name": name, "symbol": text_of(row, '[data-coin-table-target="coinSymbol"]'), "price": text_of(row, '[data-coin-table-target="price"]'), "change_24h": text_of(row, '[data-coin-table-target="priceChange24h"]'), "change_7d": text_of(row, '[data-coin-table-target="priceChange7d"]'), "volume_24h": text_of(row, '[data-coin-table-target="volume"]'), "market_cap": text_of(row, '[data-coin-table-target="marketCap"]'), }) return coins
text_of 辅助函数在行内查询一个元素并返回其去除首尾空白的文本,或在元素缺失时返回 None,确保某种代币缺少字段时不会中断循环。排名从第二列单元格读取,名称和符号来自各自的标记元素,价格、两列涨跌幅、交易量和市值各自映射到一个 data-coin-table-target 值。if not name: continue 守护跳过没有代币名称的分隔行或标题行。
CoinGecko 的类名和 data-coin-table-target 属性可能在不通知的情况下更改,且百分比涨跌幅列在窄视口上有时布局不同。请将这里的选择器视为起始模板,而非固定合约。当某个字段返回 None 时,请在浏览器开发者工具中重新检查实时页面并更新选择器。定期维护选择器是任何生产爬虫的正常工作,不是出了什么问题的标志。
步骤三:处理代币页面的分页
单个行情页面只是完整列表的一个切片。CoinGecko 使用 ?page=N 查询参数进行分页,因此您逐页收集代币到您设置的上限。在获取操作周围加一个小型重试包装,可以避免单次慢请求终止整个运行。
import time def fetch_html(page_url, max_retries=2): for attempt in range(max_retries + 1): html = crawl(page_url) if html: return html if attempt < max_retries: print(f"Retrying ({attempt + 1}/{max_retries})...") time.sleep(1) print(f"Unable to fetch {page_url}") return None def collect_all_coins(base_url, max_pages): all_coins = [] for page in range(1, max_pages + 1): page_url = f"{base_url}?page={page}" html = fetch_html(page_url) if html: all_coins.extend(parse_coins(html)) time.sleep(2) return all_coins
fetch_html 在失败时最多重试两次(中间有短暂停顿),成功时返回 HTML,放弃时返回 None。collect_all_coins 从第一页遍历到您的 max_pages 上限(防止长列表失控运行),将每页解析为代币记录并累积。页面之间的 time.sleep(2) 限制了运行速率,使您保持友好于网站的速率限制。
步骤四:组合完整脚本
现在将各部分整合到一个可运行的脚本中:遍历页面,解析每种代币,并将记录导出到 JSON 和 CSV。
import csv import json import time from crawlbase import CrawlingAPI from bs4 import BeautifulSoup api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"}) OPTIONS = { "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/122.0", "ajax_wait": "true", "page_wait": 5000, } def crawl(page_url): response = api.get(page_url, OPTIONS) if response["headers"]["pc_status"] == "200": return response["body"].decode("utf-8") print(f"Request failed: {response['headers']['pc_status']}") return None def fetch_html(page_url, max_retries=2): for attempt in range(max_retries + 1): html = crawl(page_url) if html: return html if attempt < max_retries: time.sleep(1) return None def text_of(row, selector): el = row.select_one(selector) return el.get_text(strip=True) if el else None def parse_coins(html): soup = BeautifulSoup(html, "html.parser") rows = soup.select("table tbody tr") coins = [] for row in rows: name = text_of(row, '[data-coin-table-target="coinName"]') if not name: continue coins.append({ "rank": text_of(row, "td:nth-child(2)"), "name": name, "symbol": text_of(row, '[data-coin-table-target="coinSymbol"]'), "price": text_of(row, '[data-coin-table-target="price"]'), "change_24h": text_of(row, '[data-coin-table-target="priceChange24h"]'), "change_7d": text_of(row, '[data-coin-table-target="priceChange7d"]'), "volume_24h": text_of(row, '[data-coin-table-target="volume"]'), "market_cap": text_of(row, '[data-coin-table-target="marketCap"]'), }) return coins def collect_all_coins(base_url, max_pages): all_coins = [] for page in range(1, max_pages + 1): html = fetch_html(f"{base_url}?page={page}") if html: all_coins.extend(parse_coins(html)) time.sleep(2) return all_coins def save_outputs(records): with open("coingecko_coins.json", "w") as f: json.dump(records, f, indent=2) if not records: return with open("coingecko_coins.csv", "w", newline="") as f: writer = csv.DictWriter(f, fieldnames=records[0].keys()) writer.writeheader() writer.writerows(records) def main(): coins_url = "https://www.coingecko.com/" coins = collect_all_coins(coins_url, max_pages=2) save_outputs(coins) print(f"Saved {len(coins)} coins") if __name__ == "__main__": main()
该脚本最多遍历两个行情页面,通过重试包装获取每页,将其解析为代币记录,并用两秒停顿限制循环速率。save_outputs 同时写入 JSON 文件和 CSV(以第一条记录的键作为标题),使您拥有下游工具所需格式的数据。调整 max_pages 和基础 URL,以适应您关心的市场切片。
输出示例
运行 python coingecko_scraper.py,您将得到每种代币的干净结构化记录,可直接用于分析、存入数据库或导入电子表格。以下数值是用于展示结构的示意性占位符,而非实时行情。
[ { "rank": "1", "name": "Bitcoin", "symbol": "BTC", "price": "$X,XXX.XX", "change_24h": "+1.2%", "change_7d": "-3.4%", "volume_24h": "$XX,XXX,XXX,XXX", "market_cap": "$X,XXX,XXX,XXX,XXX" }, { "rank": "2", "name": "Ethereum", "symbol": "ETH", "price": "$X,XXX.XX", "change_24h": "+0.6%", "change_7d": "+2.1%", "volume_24h": "$XX,XXX,XXX,XXX", "market_cap": "$XXX,XXX,XXX,XXX" } ]
对应的 CSV 包含相同的列,每种代币一行,可直接导入 pandas 或任意电子表格,按市值排序、按7天涨跌幅筛选或绘制交易量图表。从这里,相同的模式也适用于其他行情追踪工具;这种方法与 从 CoinMarketCap 爬取加密货币价格的方式非常接近。
大规模运行时保持不被屏蔽
即使渲染问题已解决,CoinGecko 仍会监测爬虫特征的流量。以下几个习惯可以保持较长时间运行的健康,适用于任何高流量数据网站。
- 限制请求速率。在紧密循环中猛烈请求页面是最快被限速或挑战的方式。上面的两秒停顿是下限,而非上限;对于较大的任务请适当延长,并遵守网站发布的速率限制。
- 依赖 IP 轮换。住宅 IP 池将请求分散到众多真实用户地址,使任何单个地址都不会触发速率限制。Crawling API 为您处理这些;如果您自己搭建技术栈,这是最关键的部分。
-
读取状态码。当运行开始返回非 200 的
pc_status值时,说明当前速率或 IP 等级已不够用。将其视为退让的信号,而非可以忽略的噪声。
对于较大规模的爬取,异步 Crawler 可将请求排队并通过 webhook 交付结果,适合在不保持开放连接的情况下运行多个页面。有关更广泛的策略,请参阅 如何在不被屏蔽的情况下爬取网站。
爬取 CoinGecko 是否合法?
先说明更好的路径:CoinGecko 发布了官方公开 API,以干净的 JSON 格式返回代币名称、符号、价格、市值、24小时交易量、百分比变化和排名,并有文档化的速率限制和付费层供更高吞吐量使用。对于任何生产或商业用途,该 API 是经过授权的路径,既更稳定,也比解析渲染 HTML 更尊重平台。本指南中的 HTML 爬取方式是一种教学性备选方案,适用于页面专属字段或一次性探索,而非在官方 API 存在时的替代品。
爬取网站本身是否被允许,取决于 CoinGecko 的服务条款、您所在的司法管辖区以及您对数据的用途。请阅读 CoinGecko 的条款和其 robots.txt,并将两者视为您采集内容和频率的边界。将请求量控制在不给服务器造成负担的水平,对于轻量偶尔使用以外的任何情况请优先使用 API。这里的行情数据是事实性、非个人性的,比用户生成内容的风险更低,但条款仍然约束自动访问。
本指南刻意将范围限定在公开行情数据:任何人无需账号即可看到的代币名称、符号、价格、市值、交易量、百分比变化和排名。它不涵盖登录墙或付费墙后面的任何内容、任何个人或账户数据,或 CoinGecko 的品牌、Logo 或编辑内容的再发行(这些仍是其财产)。如果您的项目需要可靠的大规模访问,正确路径是 CoinGecko 的官方 API 或授权数据源,而非更复杂的爬虫。如需更广泛了解数据提供商,请参阅 全球最佳金融数据提供商。
核心要点
- 优先使用 API。CoinGecko 的官方公开 API 以 JSON 格式返回名称、符号、价格、市值、交易量、涨跌幅和排名,是任何生产工作负载的正确路径。
-
HTML 爬取是备选方案。需要爬取页面时,由于页面部分是客户端渲染的,请在解析前使用 Crawling API 的 JS token 进行渲染;
ajax_wait和page_wait控制等待时长。 -
通过数据属性定位。CoinGecko 使用
data-coin-table-target值标记其行情单元格,因此按属性而非脆弱的列位置读取每个字段。 -
分页并导出。沿 CoinGecko 的
?page=N页面遍历到上限,用短暂停顿限制运行速率,并将记录写入 JSON 和 CSV。 - 坚守公开数据。遵守 CoinGecko 的服务条款、robots.txt 和速率限制,仅采集公开行情数据,绝不触碰登录账户、付费内容或受版权保护的内容。
常见问题
我应该使用 CoinGecko API 还是爬取 HTML?
使用 API。CoinGecko 提供免费的公开 API,以干净的 JSON 格式返回代币名称、符号、价格、市值、24小时交易量、百分比变化和排名,并有文档化的速率限制。它比解析 HTML 更稳定,是生产用途的授权路径。仅在您所使用的 API 层不公开的字段或视图时才爬取渲染页面,且在此情况下也请遵守相同的速率限制。
为什么普通请求只返回部分 CoinGecko 表格?
因为 CoinGecko 通过 JavaScript 在客户端补充其行情表格的大部分内容:价格和百分比变化实时更新,部分单元格只有在浏览器中运行页面脚本后才会填充。原始 HTTP 请求可能返回状态码 200 但表格数据不完整。要获取完整的行集合,您需要先渲染页面,这正是 Crawling API 的 JS token 为您处理的事情。
CoinGecko 需要普通 token 还是 JS token?
JS token。普通 token 获取静态 HTML,在部分客户端渲染的页面上可能错过实时单元格。JS token 在返回 HTML 之前先在真实浏览器中渲染页面,确保当 BeautifulSoup 解析时,代币行及其价格、涨跌幅、交易量和市值单元格都已存在。
我可以从 CoinGecko 提取哪些数据?
公开行情数据:代币名称和符号、当前价格、市值、24小时交易量、24小时和7天百分比变化以及市值排名。这是任何访客都可以看到的事实性、非个人性行情数据。请远离登录墙或付费墙后面的任何内容,不要转载 CoinGecko 的 Logo、品牌或编辑内容。
我的选择器返回 None,是什么发生了变化?
几乎可以肯定是 CoinGecko 的标记发生了变化。其类名和 data-coin-table-target 属性可能在不通知的情况下更改,且百分比涨跌幅列在窄视口上布局不同。请在浏览器开发者工具中重新检查实时页面并更新选择器。定期维护选择器是任何生产爬虫的正常工作,这也是应尽可能优先使用官方 API 的另一个原因。
我可以将爬取的 CoinGecko 数据用于商业用途吗?
请将其视为法律问题而非技术问题。CoinGecko 的服务条款约束自动访问和再利用,商业或大规模用途通常应使用其官方 API 或付费层,而非爬虫。请审阅条款,对于任何大规模用途使用 API 或授权数据源,并在基于这些数据构建产品之前寻求法律建议。
大规模爬取任何站点,无需与基础设施对抗。
Crawlbase 负责处理代理、指纹和 CAPTCHA,让你的团队专注于交付数据流水线,而非维护爬取管道。1,000 次请求免费,无需信用卡。
