使用ensemble数据库的REST API获取基因长度信息

如题。想批量获取基因信息,但是不想下载整个数据库,搜索相关资料时发现了这个API,遂探索了一下用法。

背景

Ensembl数据库是一个广泛使用的基因组数据库,它为科研人员提供了丰富的基因组信息,包括基因、转录本、蛋白质等的数据。

REST API,全称Representational State Transfer API,是一种网络应用程序的设计风格和开发方式,它基于HTTP协议,可以使用XML或者JSON格式传输数据,使得用户可以通过编程语言轻松访问网络资源。换言之,用户可以简单的对这一API的网址发送一个请求,就可以以json文档或xml文档的形式获得所需数据,其远比本地构建数据库或使用网络爬虫要灵活得多。

Ensembl数据库提供了一个REST API接口(https://rest.ensembl.org/),用户可以通过这个接口使用编程语言查询基因组信息,这为科研人员提供了一个方便、快捷的方式来获取和处理数据。

Ensembl REST API获取基因信息

Ensembl REST API Endpoints这个页面上详细介绍了这些API的URL和使用方法。

我们以Loolup这个API为例,展示一下如何获取基因信息。如下图是官网页面对这一API的描述,可以看到,其主要涉及两个URL,分别是https://rest.ensembl.org/lookup/id/https://rest.ensembl.org/lookup/symbol/<spcies>/。这两个URL都可以接受GET请求和POST请求(关于GET和POST的区别请参考这篇文章),其中GET通常用于查询单个实体,而POST可以用于批量查询。

image.png

在Ensembl数据库中,每个基因都会被分配一个特定的ID,且不同物种之间的同源基因的ID不同,因此给定基因ID可以直接定位到某一个特定的基因;相比之下,一个基因symbol可以对应到多个物种中的同源基因,因此REST API接口在设计的时候就指定,如果传入的是基因symbol,则还需要一并传入物种名称。

要使用Ensembl数据库的REST API接口获取基因信息,我们需要知道基因的ID,然后构造一个URL,通过HTTP GET请求这个URL,就可以得到一个包含基因信息的JSON文档。

例如,要查询基因ID为ENSG00000157764的基因信息,我们可以构造如下URL:

1
https://rest.ensembl.org/lookup/id/ENSG00000157764?expand=1;content-type=application/json

然后,你可以使用Python等编程语言发起一个HTTP GET请求,获取这个URL的内容,解析得到的JSON文档,就可以得到这个基因的信息了。

下面是一个使用Python的requests库发起HTTP GET请求的示例代码:

1
2
3
4
5
6
7
8
9
import requests
import json
# 构造URL
url = "https://rest.ensembl.org/lookup/id/ENSG00000157764?expand=1;content-type=application/json"
# 发起GET请求
response = requests.get(url)
data = response.json() # requests库的response对象支持调用`json()`方法直接将响应结果转换为python dict
# 打印响应内容
print(json.dumps(data,indent="\t"))

运行这段代码,可以在控制台看到包含基因信息的JSON文档(如下图)。当然我们也可以直接对dict对象(即上述代码中的data)进行操作,获得更精细的信息。

image.png

如果我们需要批量查询多个基因的信息,则可以使用HTTP POST请求,将基因的ID列表作为payload发送给服务器。下面是一个使用Python的requests库发起HTTP POST请求的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import requests
import json
# 构造URL
url = "https://rest.ensembl.org/lookup/id/"
# 构造payload
payload = {
    "ids": ["ENSG00000157764", "ENSG00000139618"],
    "expand": 0 # 这个参数控制是否查询Transcript、exon等相关信息。设置为0可以缩短响应时间
}
# 发起POST请求
response = requests.post(url, json=payload)
data = response.json()
# 打印响应内容
print(json.dumps(data,indent="\t"))

运行这段代码,可以在控制台看到包含多个基因信息的JSON文档(如下图)。同样的,我们也可以直接对dict对象进行操作,获得更精细的信息。

image.png

最后是我自己写的两个函数,分别用于获取基因全长和转录本长度。分享于此,仅供参考。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import requests
import json

## 基于ensemble RUST API的基因长度批量获取函数。
# 参考:https://rest.ensembl.org/documentation/info/lookup_post
# 这里获取的是基因的总长度,即start-end,并非转录本长度。
def getEnsembleGeneLength(ensembl_id_list,return_rawjson=False):
# @param ensembl_id_list: A list of query ensembl ID
# @param return_rawjson: if True, return raw response json;else, return a list of gene length
# @return A list of gene length corresponding to the query ensembl ID list,or raw json
url = f"https://rest.ensembl.org/lookup/id?expand=0"
payload = { "ids" : ensembl_id_list }
headers = { "Content-Type" : "application/json", "Accept" : "application/json"}
response = requests.post(url, headers=headers, data=json.dumps(payload))
if response.status_code != 200:
return None
else:
data = response.json()
if(return_rawjson): return(data)
gene_length_list = []
for ensembl_id in ensembl_id_list:
if(ensembl_id in data):
try:
data1 = data[ensembl_id]
gene_length_list.append(abs(data1["start"]-data1["end"]))
except Exception as e:
print(f"Warning: gene {ensembl_id} have no length info. message: {e}")
gene_length_list.append(None)
else:
gene_length_list.append(None)
return gene_length_list

## 基于ensemble RUST API的基因长度批量获取函数。
# 参考:https://rest.ensembl.org/documentation/info/lookup_post
# 这里获取的是基因的transcript长度.
import pandas as pd
def getEnsembleTransLength(ensembl_id_list,return_rawjson=False,return_transcript_df=False):
# @param ensembl_id_list: A list of query ensembl ID
# @param return_rawjson: if True, return raw response json;else, return a list of gene length
# @param return_transcript_df: if True, return all genes' all transcripts' length as a list of dataframe; else, only return the length of the longest transcript of each gene
# @return A list of gene length corresponding to the query ensembl ID list
url = f"https://rest.ensembl.org/lookup/id?expand=1"
payload = { "ids" : ensembl_id_list }
headers = { "Content-Type" : "application/json", "Accept" : "application/json"}
response = requests.post(url, headers=headers, data=json.dumps(payload))
if response.status_code != 200:
return (None,None)
else:
data = response.json()
if(return_rawjson): return(data)
gene_length_list = []
max_transcript_length_list= []
transcript_length_df_list = []
for ensembl_id in ensembl_id_list:
if(ensembl_id in data):
try:
data1 = data[ensembl_id]
gene_length_list.append(abs(data1["start"]-data1["end"]))
transcript_list = data1["Transcript"]
transcript_id_list = []
transcript_length_list = []
for transcript in transcript_list:
if("Exon" in transcript):
transcript_id_list.append(transcript["id"])
exons = transcript["Exon"]
transcript_length = 0
for exon in exons:
transcript_length += abs(exon["start"]-exon["end"])
transcript_length_list.append(transcript_length)
max_transcript_length_list.append(np.max(transcript_length_list))
if(return_transcript_df):
df = pd.DataFrame({"id":transcript_id_list,"length":transcript_length_list})
#display(df)
transcript_length_df_list.append(df)
except Exception as e:
print(f"Warning: gene {ensembl_id} have no transcript length info. message: {e}")
gene_length_list.append(None)
max_transcript_length_list.append(None)
transcript_length_df_list.append(None)
else:
gene_length_list.append(None)
max_transcript_length_list.append(None)
transcript_length_df_list.append(None)
if(return_transcript_df):
return (gene_length_list,transcript_length_df_list)
else:
return (gene_length_list,max_transcript_length_list)

以上。