☰
KEGG数据库结构与API数据获取实战:从通路注释到工程化分析
2026/10/31 3:51:57 网站建设 项目流程

KEGG 这个名词,做生物信息的人几乎绕不开。我最早接触它是在一次代谢通路富集分析里,当时对着一堆通路图发懵,不知道那些方框、圆圈和连线到底在讲什么,更不知道背后的数据是怎么组织的。后来项目做多了,才慢慢摸清它的脾气——它不只是一个"画通路图的网站",本质上是一套把基因、蛋白、代谢物、疾病、药物串起来的关系数据库体系,而且提供了相当完整的 API 接口,能让我们把数据拉下来做批量处理。

这篇东西我想聊的是 KEGG 数据库本身的结构,以及怎么通过它的 API 把数据拿到手、用起来。适合两类人看:一类是刚进组、被导师丢了一句"你去查查 KEGG 通路"的新手,另一类是已经会用但总觉得数据来源不够透明、想搞清楚底层逻辑的老手。我会从数据库的组织方式讲起,然后落到 API 的实际调用,中间穿插我自己踩过的坑和几个容易被忽略的细节。核心关键词就三个:KEGG 数据库、通路注释、API 数据获取。

1. KEGG 到底由哪几块拼起来

很多人以为 KEGG 就是一个通路图库,这个理解不算错,但太窄了。它其实是一个由多个子数据库组成的联合体,每个子库负责一类实体,彼此之间通过统一的标识符体系互相引用。搞清楚这个结构,后面调 API 的时候你才知道该去哪个端点拿什么数据。

1.1 三大类子库的分工

KEGG 的子库大致可以分成三组。第一组是通路相关的,核心是 KEGG PATHWAY,也就是我们最常看的那张代谢或信号通路图;配套的还有 KEGG MODULE(功能单元,比通路更细,比如某个具体的降解模块)和 KEGG BRITE(层级分类体系,把基因、蛋白按功能归类)。

第二组是基因组与分子实体相关的,包括 KEGG GENES(各物种的基因信息)、KEGG GENOME(物种基因组)、KEGG ORTHOLOGY(直系同源基因,也就是 KO 编号的来源)、KEGG COMPOUND(化合物)、KEGG REACTION(生化反应)、KEGG ENZYME(酶)。这一组是通路图的"零件库",通路图上的每个节点基本都能在这里找到对应的条目。

第三组是表型与应用相关的,比如 KEGG DISEASE(疾病)、KEGG DRUG(药物)、KEGG GLYCAN(聚糖)等。做药物靶点或者疾病机制研究的人会经常用到这一组。

这三组之间的关系是:通路图把分子实体组织成功能网络,而表型类子库又把分子实体和临床、药物信息关联起来。理解这个"零件—网络—应用"的三层结构,你在设计分析流程时就不会迷路。

1.2 标识符体系:为什么 KO 号这么重要

KEGG 里最关键的标识符是KO 编号(K 开头,比如 K00001)。KO 代表直系同源基因的功能分类,一个 KO 号对应一组在不同物种中功能相同的基因。为什么它重要?因为不同物种的基因编号(比如人的基因、小鼠的基因)各不相同,但它们的 KO 号是统一的。做跨物种比较或者富集分析时,我们通常先把各物种的基因映射到 KO,再基于 KO 去做通路富集。

除了 KO,还有几个常见前缀需要记住:map开头的是参考通路(如 map00010 是糖酵解),hsa开头的是人类专属通路(hsa00010),C开头是化合物,R开头是反应,ec开头是酶。这些前缀在调 API 时直接决定了你请求的 URL 路径,记混了就会拿到空结果。

提示:同一个通路在不同物种下有不同的编号前缀,但底层拓扑结构是共享的。做富集时用参考通路编号(map 开头)更通用,做物种特异性分析时才用物种前缀。

1.3 通路图的两种呈现:参考图与物种图

KEGG 通路图有两种形态。一种是参考通路图,把所有物种里出现过的基因都画上去,节点用 KO 号标注,这是"全集"。另一种是物种特异性通路图,只保留该物种实际拥有的基因,节点用该物种的基因编号标注。

这个区别在实际操作中很要命。如果你拿参考通路图去对照某个物种的基因列表,会发现很多节点在该物种里根本不存在;反过来,如果你只用物种图,又会丢失跨物种比较的视角。我的习惯是:做单物种分析用物种图,做多物种整合或者方法学展示用参考图,两者配合着看。

2. 调 API 之前必须想清楚的三件事

KEGG 提供了 REST 风格的 API,基础地址是https://rest.kegg.jp/,操作类型通过路径段来区分,比如get、list、find、link、conv等。看起来简单,但直接上手就调往往会碰壁。我在实际项目里总结出三个必须先想清楚的问题,想清楚了再写代码,能省掉大量返工。

2.1 你要的是"列表"还是"条目详情"

这是最容易搞混的一点。list操作返回的是标识符列表,比如list/pathway/hsa会返回人类所有通路的编号和名称,但它不包含通路内部的基因信息。而get操作返回的是具体条目的详细内容,比如get/hsa00010会返回糖酵解通路的完整记录,包括基因、化合物、反应等。

很多人一上来就想拿"某个通路里有哪些基因",结果用了list,拿到的只是一堆通路名,然后纳闷为什么没有基因。正确的做法是两步走:先用list拿到通路编号,再用link或者get去拿通路和基因的关联。link是专门用来查两个实体之间关联的操作,比如link/hsa/hsa00010就是查人类基因和糖酵解通路的对应关系。

2.2 请求频率与批量策略

KEGG 的 API 对访问频率是有约束的,虽然没有公开一个精确的阈值,但短时间内高频请求会被限流甚至临时拒绝。我在早期项目里图省事,写了个循环把几百个通路一个个get下来,跑到一半就开始返回错误,排查了半天才意识到是频率问题。

后来我的做法是:能批量就批量。KEGG 的 API 支持在路径里用+拼接多个标识符,比如get/hsa00010+hsa00020一次拿两个通路。对于大批量任务,我会在请求之间加一个短暂的间隔(比如 0.3 到 0.5 秒),并且做好失败重试。另外,把结果缓存到本地是必须的——同一个数据反复请求既浪费配额又慢,落盘之后后续分析直接读本地文件。

2.3 返回格式的选择

KEGG API 默认返回纯文本格式,但很多操作支持通过参数指定返回 JSON。文本格式的好处是紧凑、易读,适合快速查看;JSON 的好处是结构化、好解析,适合写进程序。我的经验是:探索阶段用文本格式肉眼看,正式流程里用 JSON 解析。

不过要注意,不是所有端点都支持 JSON,具体要看操作类型。get和list一般可以通过在 URL 后加格式参数来切换,但有些老端点只吐文本。写代码时最好对返回内容做个格式判断,别硬编码解析逻辑。

3. 几个高频 API 操作的实操拆解

光讲概念没用,这一节我把几个最常用的操作拆开讲,每个都给请求示例、返回内容说明和使用场景。这些是我在真实项目里反复用到的,不是照搬文档。

3.1 用 list 摸清数据边界

第一步永远是搞清楚"有哪些东西"。比如你想做人类代谢通路分析,先得知道人类有多少条通路、编号长什么样。

# 列出人类所有通路 curl "https://rest.kegg.jp/list/pathway/hsa"

返回的是每行一个通路,格式是"通路编号\t通路名称"。这里有个细节:名称里可能包含分号分隔的多个别名,解析时要注意按制表符切分,别把名称里的分号也当分隔符。

再比如列出所有物种:

curl "https://rest.kegg.jp/list/organism"

这个返回里包含物种的三字母代码(比如 hsa 是人类、mmu 是小鼠),这个代码就是后面所有请求里要用的物种前缀。我见过有人拿物种全名去请求,结果当然是空的——API 只认三字母代码。

3.2 用 link 建立实体关联

link是我用得最多的操作,因为它直接回答"A 和 B 有什么关系"。常见用法有三种:

# 查某个通路包含哪些基因 curl "https://rest.kegg.jp/link/hsa/hsa00010" # 查某个基因参与哪些通路 curl "https://rest.kegg.jp/link/pathway/hsa:10327" # 查通路和 KO 的对应关系 curl "https://rest.kegg.jp/link/ko/hsa00010"

返回格式是两列,第一列是源实体,第二列是目标实体,用制表符分隔。这里要注意方向:link/目标/源的顺序,第一个路径段是你想查到的目标类型,第二个是已知的源。写反了虽然不一定报错,但结果会让你困惑。

我踩过的一个坑是:link/hsa/hsa00010返回的是基因编号(比如 10327),而不是基因符号(比如 ALDH1A1)。要拿基因符号,还得再get一次基因条目,或者用conv做编号转换。这个链路在设计流程时要提前规划好,别到后面才发现拿到的是一堆数字。

3.3 用 find 做关键词检索

当你不知道确切编号、只有一个关键词时,find就派上用场了。

# 在人类基因里搜关键词 curl "https://rest.kegg.jp/find/hsa/glucose" # 在化合物里搜 curl "https://rest.kegg.jp/find/compound/glucose"

find是在名称和描述里做子串匹配,返回匹配到的条目。它的局限是只做字面匹配,不理解语义,所以搜"糖代谢"这种中文概念是没用的,得用英文关键词。另外,搜索结果可能很多,需要自己再做筛选。

3.4 用 conv 做编号体系转换

不同数据库用的编号体系不一样,conv就是用来在 KEGG 编号和外部编号之间转换的。比如把 KEGG 基因编号转成 NCBI 的 Gene ID:

curl "https://rest.kegg.jp/conv/ncbi-geneid/hsa"

这个操作在做数据整合时特别有用。比如你手上有一批 NCBI Gene ID,想映射到 KEGG 通路,就得先conv成 KEGG 基因编号,再link到通路。整个链路是:外部编号 → conv → KEGG 基因 → link → 通路。少一步都接不上。

4. 把 API 数据接进分析流程的完整链路

单次调 API 只是拿数据,真正有价值的是把数据组织成能支撑分析的形态。这一节我讲一个完整的、从原始请求到可用结果的链路,以"给定一批人类基因,找出它们富集在哪些通路上"为例。

4.1 数据获取阶段的组织方式

第一步是拿到基因和通路的全量关联。与其针对每个基因去查,不如一次性把人类所有基因-通路关联拉下来,存成本地表。请求是:

curl "https://rest.kegg.jp/link/pathway/hsa" -o hsa_gene_pathway.tsv

这个请求返回人类所有基因和所有通路的关联对,数据量不小但一次到位。落盘之后,后续任何基因列表的富集都可以在这张表上做连接,不用再联网。

同样的思路,把通路名称表、KO 关联表也各拉一份:

curl "https://rest.kegg.jp/list/pathway/hsa" -o hsa_pathway_names.tsv curl "https://rest.kegg.jp/link/ko/hsa" -o hsa_gene_ko.tsv

这三张表构成了本地分析的基础。我一般会用一个脚本统一管理这些下载任务,加上重试和校验(比如检查文件行数是否合理),避免某次网络抖动导致拿到残缺数据却不知道。

4.2 编号对齐:最容易被低估的环节

拿到数据后第一个坎是编号对齐。你手上的基因列表可能是基因符号(如 TP53),而 KEGG 关联表里是基因编号(如 7157)。这中间的转换有两种办法:一是用conv把 KEGG 编号转成 NCBI Gene ID 再和你的数据对齐,二是用find或get拿到基因符号再做匹配。

我倾向于第一种,因为编号是稳定的,符号可能因为别名、大小写、新旧命名而变化。实际操作中,我会先建一张"KEGG 基因编号 ↔ 基因符号 ↔ NCBI Gene ID"的映射表,后续所有对齐都走这张表。这张表本身也是通过 API 拉取基因条目后解析出来的。

注意:基因符号存在大量别名和历史命名,直接按符号匹配的失败率比想象中高。能用编号就用编号,符号只作为展示用。

4.3 富集计算与结果解读

有了基因-通路关联表和编号映射,富集计算本身并不复杂:对每个通路,统计你的基因列表里落在该通路的基因数,和背景期望做比较,算一个显著性。这里不展开统计细节,重点说数据层面的两个注意点。

第一,背景基因集的选择直接影响结果。如果你只把"有 KEGG 注释的基因"当背景,和把"全基因组"当背景,算出来的显著性差别很大。我的做法是明确记录背景集是怎么来的,并在结果里注明,避免别人复现时对不上。

第二,通路大小的影响。特别大的通路(比如代谢通路往往包含上百个基因)容易因为基因多而显得显著,特别小的通路又容易因为偶然命中而假阳性。解读时要结合通路规模和实际生物学意义,别只看 p 值。

4.4 结果落盘与可复现性

整个链路跑完后,我会把中间产物全部保留:原始 API 返回、解析后的关联表、映射表、富集结果。每一份都带上下载或生成的时间戳。这样做的好处是,几个月后回头查某个结果,能清楚知道当时用的是哪个版本的数据。

KEGG 的数据是持续更新的,通路会增删、基因注释会修订。如果不记录数据版本,同一个分析在不同时间跑出来的结果可能不一致,这在需要复现的项目里是致命的。我现在的习惯是每次正式分析前先拉一次全量数据,存成带日期的快照,分析只读快照。

5. 那些文档里不会写的坑

这一节是我这些年攒下来的经验,都是实际踩过之后才明白的,官方文档里基本不会提。

5.1 物种代码不是想当然的

物种三字母代码有历史遗留问题,不是简单按学名缩写来的。比如人类是 hsa,小鼠是 mmu,大鼠是 rno,这些还好记;但有些物种的代码和直觉差很远,靠猜基本猜不中。正确做法是先list/organism拿到全表,再按名称检索。我见过有人硬编码了一个猜测的代码,跑了一晚上返回全是空,第二天才发现代码错了。

5.2 通路编号的前缀陷阱

前面提过 map 和物种前缀的区别,这里再强调一个具体场景:做富集时如果用物种前缀(如 hsa00010),拿到的是该物种特有的通路记录;如果用 map 前缀(map00010),拿到的是参考通路。两者包含的基因集合可能不同。如果你的基因列表来自人类,却用 map 前缀去关联,可能会引入该物种没有的基因,或者漏掉物种特有的基因。统一用哪个前缀,要在流程设计时就定死,别混用。

5.3 返回内容的编码与分隔符

KEGG API 返回的文本里,字段分隔符是制表符,但有些字段内部(比如通路名称)可能包含空格、分号、括号。解析时如果简单地按空白切分,会把名称切碎。稳妥的做法是按制表符切分,然后对每个字段单独处理。另外,返回内容里偶尔会有非 ASCII 字符(比如某些化合物名称里的特殊符号),读取时要确保用 UTF-8 编码,否则会出现乱码。

5.4 批量请求的失败处理

批量请求一定会遇到失败,这不是"会不会"的问题,是"什么时候"的问题。失败的原因可能是网络抖动、频率限制、服务端临时不可用。我的处理策略是三层:第一层是请求间隔,避免触发限流;第二层是失败重试,带指数退避;第三层是结果校验,检查返回内容是否符合预期格式,不符合就当作失败重试。

这里有个细节:重试不能无脑重试同一个请求,如果是因为频率限制失败,立刻重试只会继续失败。指数退避的意思是第一次等 1 秒,第二次等 2 秒,第三次等 4 秒,以此类推,给服务端喘息的时间。

5.5 数据更新带来的结果漂移

KEGG 的数据不是静态的。通路会新增、基因注释会修订、某些条目会被合并或拆分。这意味着你半年前跑的分析,今天用同样的代码跑,结果可能不一样。这不是 bug,是数据在演进。

应对办法有两个:一是固定数据快照,分析只读快照,保证可复现;二是在报告里注明数据获取日期,让读者知道结果对应的是哪个时间点的数据。我现在的项目里,数据快照是标配,没有快照的分析结果我不认。

6. 从单次调用到工程化使用的思路

如果你只是偶尔查一两个通路,手动调 API 完全够用。但如果要把 KEGG 数据接进一个持续运行的分析流程,就得考虑工程化的问题。这一节聊聊我在这方面的实践思路。

6.1 封装一层客户端

直接在每个脚本里写curl或者裸调 HTTP 库,短期看省事,长期看是灾难——请求逻辑、重试、缓存、解析散落各处,改一处要动很多地方。我的做法是封装一个轻量的客户端,把"请求—重试—解析—缓存"这套逻辑收进去,上层只调方法。

这个客户端至少要有几个能力:统一的请求入口(处理 URL 拼接和格式参数)、自动重试(带退避)、本地缓存(按请求 URL 做键,命中就返回缓存)、返回内容的结构化解析。封装好之后,上层代码就变成"我要某个通路的所有基因"这样一句话,底层细节全透明。

6.2 缓存策略的设计

缓存不是简单地把返回存下来就完事,要考虑失效和更新。KEGG 数据会变,缓存不能永久有效。我的策略是:缓存带时间戳,超过一定周期(比如一周)就视为过期,下次请求时重新拉取。对于明确知道不会变的数据(比如某个历史版本的通路记录),可以标记为长期缓存。

另外,缓存要能区分不同的请求参数。同一个端点,带不带格式参数、带哪些标识符,返回是不同的,缓存键必须把这些都编码进去,否则会串数据。

6.3 数据版本管理

前面反复提到数据快照,这里说具体怎么做。我的做法是每次全量拉取时,把数据存到一个带日期的目录下,同时在目录里放一个清单文件,记录每个文件的来源 URL、行数、校验和。分析脚本读取数据时,从清单里拿路径,而不是硬编码。

这样做的好处是,任何时候都能回答"这个结果用的是哪天的数据",也能在数据出问题时快速定位是哪个文件坏了。清单文件本身很小,但价值很大。

6.4 与其他数据源的衔接

KEGG 很少单独使用,通常要和别的数据源配合。比如基因编号要和 NCBI 对齐,化合物要和 PubChem 对齐,通路要和 GO 或 Reactome 做交叉验证。这些衔接点都要在工程化设计时预留好接口。

我的经验是,把"编号映射"做成独立的一层,所有跨数据源的转换都走这一层。这样当某个数据源的编号体系变化时,只需要改映射层,不用动上层分析逻辑。映射层的数据本身也来自 API 拉取,同样要缓存和版本管理。

7. 一些实际使用中的判断经验

最后聊几个偏"感觉"的东西,这些没法写成精确的规则,但实际用起来很影响效率。

关于什么时候用参考通路、什么时候用物种通路,我的判断标准是看分析目的。如果目的是"这个物种的代谢特征",用物种通路;如果目的是"这个方法能不能推广到多物种",用参考通路。两者不是对错问题,是视角问题。

关于富集结果的解读,我越来越倾向于不只看显著性,还要看通路之间的拓扑关系。KEGG 通路不是孤立的,代谢通路之间有前体-产物的连接,信号通路之间有上下游关系。一个基因同时落在几个相关通路上,比落在几个毫不相干的通路上更有生物学意义。这个判断需要你对通路图本身有理解,光看统计表是看不出来的。

关于数据获取的粒度,我的原则是"宁可多拉,不要少拉"。全量拉一次存本地,比反复按需请求要稳得多。存储成本很低,反复请求的时间成本和失败风险反而更高。当然,前提是做好缓存和版本管理,别让本地数据变成一团乱麻。

这套东西我用了几年,从最开始的手动查网页,到后来的脚本调用,再到现在的客户端封装加数据快照,每一步都是被实际问题逼出来的。KEGG 的 API 本身不复杂,复杂的是围绕它的数据组织、编号对齐和可复现性。把这几件事想清楚,剩下的就是写代码的体力活了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询