存取 NCBI 的 Entrez 資料庫

Entrez (https://www.ncbi.nlm.nih.gov/Web/Search/entrezfs.html) 是一個資料檢索系統,讓使用者可以存取 NCBI 的資料庫,例如 PubMed、GenBank、GEO 和許多其他資料庫。您可以從網頁瀏覽器存取 Entrez 以手動輸入查詢,或者您可以使用 Biopython 的 Bio.Entrez 模組以程式化的方式存取 Entrez。後者允許您例如從 Python 腳本內搜尋 PubMed 或下載 GenBank 記錄。

Bio.Entrez 模組使用 Entrez 程式設計工具(也稱為 EUtils),該工具由八個工具組成,這些工具在 NCBI 的頁面 (https://www.ncbi.nlm.nih.gov/books/NBK25501/) 上有詳細描述。這些工具中的每一個都對應於 Bio.Entrez 模組中的一個 Python 函數,如下面的章節所述。此模組確保使用正確的 URL 進行查詢,並遵循 NCBI 的負責數據存取指南。

Entrez 程式設計工具傳回的輸出通常為 XML 格式。要解析此類輸出,您有幾種選擇

  1. 使用 Bio.Entrez 的解析器將 XML 輸出解析為 Python 物件;

  2. 使用 Python 標準函式庫中提供的 XML 解析器之一;

  3. 將 XML 輸出讀取為原始文字,並透過字串搜尋和操作來解析它。

有關 Python 標準函式庫中 XML 解析器的說明,請參閱 Python 文件。在這裡,我們討論 Biopython 的 Bio.Entrez 模組中的解析器。此解析器可用於解析透過 Bio.Entrez 的程式化存取函數提供給 Entrez 的資料,也可以用於解析儲存在檔案中的 NCBI Entrez 的 XML 資料。在後一種情況下,XML 檔案應以二進制模式開啟(例如 open("myfile.xml", "rb")),以便 Bio.Entrez 中的 XML 解析器正常運作。或者,您可以將 XML 檔案的檔名或路徑傳遞給它,讓 Bio.Entrez 處理檔案的開啟和關閉。

NCBI 使用 DTD(文件類型定義)檔案來描述 XML 檔案中包含的資訊結構。Biopython 發行版中包含 NCBI 使用的大多數 DTD 檔案。Bio.Entrez 解析器在解析 NCBI Entrez 傳回的 XML 檔案時會使用 DTD 檔案。

有時,您可能會發現 Biopython 發行版中缺少與特定 XML 檔案相關聯的 DTD 檔案。特別是,當 NCBI 更新其 DTD 檔案時,可能會發生這種情況。如果發生這種情況,Entrez.read 將顯示一則警告訊息,其中包含遺失的 DTD 檔案的名稱和 URL。解析器將繼續透過網際網路存取遺失的 DTD 檔案,以便繼續解析 XML 檔案。但是,如果 DTD 檔案可在本機使用,則解析器會快得多。為此,請從警告訊息中的 URL 下載 DTD 檔案,並將其放置在 ...site-packages/Bio/Entrez/DTDs 目錄中,其中包含其他 DTD 檔案。如果您沒有此目錄的寫入權限,您也可以將 DTD 檔案放置在 ~/.biopython/Bio/Entrez/DTDs 中,其中 ~ 代表您的主目錄。由於此目錄會在 ...site-packages/Bio/Entrez/DTDs 目錄之前讀取,因此如果 ...site-packages/Bio/Entrez/DTDs 中的 DTD 檔案過時,您也可以將較新版本的 DTD 檔案放在那裡。或者,如果您是從原始碼安裝 Biopython,您可以將 DTD 檔案新增到原始碼的 Bio/Entrez/DTDs 目錄,然後重新安裝 Biopython。這會將新的 DTD 檔案與其他 DTD 檔案一起安裝在正確的位置。

Entrez 程式設計工具也可以產生其他格式的輸出,例如序列資料庫的 Fasta 或 GenBank 檔案格式,或文獻資料庫的 MedLine 格式,詳見 專門的解析器 章節。

Bio.Entrez 中用於程式化存取 Entrez 的函數會以二進制格式或文字格式傳回資料,具體取決於要求的資料類型。在大多數情況下,這些函數會透過將從 NCBI Entrez 取得的資料解碼為 Python 字串,並假設編碼為 UTF-8,以文字格式傳回資料。但是,XML 資料會以二進制格式傳回。原因是在 XML 文件本身中指定了編碼,這表示在開始解析檔案之前,我們不會知道要使用的正確編碼。Bio.Entrez 的解析器因此會接受二進制格式的資料,從 XML 中提取編碼,並使用它將 XML 文件中的所有文字解碼為 Python 字串,以確保所有文字(特別是英文以外的語言)都能正確解譯。這也是為什麼當您想要使用 Bio.Entrez 的解析器來解析檔案時,應該以二進制模式開啟 XML 檔案的原因。

Entrez 指南

在使用 Biopython 存取 NCBI 的線上資源(透過 Bio.Entrez 或其他一些模組)之前,請閱讀 NCBI 的 Entrez 使用者要求。如果 NCBI 發現您濫用其系統,他們可以而且將會禁止您存取!

總結一下

  • 對於任何超過 100 次請求的系列,請在週末或美國尖峰時間之外執行。這取決於您是否遵守。

  • 使用 https://eutils.ncbi.nlm.nih.gov 位址,而不是標準的 NCBI 網頁位址。Biopython 使用此網頁位址。

  • 如果您正在使用 API 金鑰,則每秒最多可以發出 10 個查詢,否則每秒最多可以發出 3 個查詢。Biopython 會自動強制執行此限制。在引數清單中包含 api_key="MyAPIkey" 或將其設定為模組級變數

    >>> from Bio import Entrez
    >>> Entrez.api_key = "MyAPIkey"
    
  • 使用選用的電子郵件參數,以便 NCBI 在出現問題時可以與您聯繫。您可以明確地將其設定為每次呼叫 Entrez 的參數(例如,在引數清單中包含 email="A.N.Other@example.com"),或者您可以設定全域電子郵件位址

    >>> from Bio import Entrez
    >>> Entrez.email = "A.N.Other@example.com"
    

    Bio.Entrez 隨後將在每次呼叫 Entrez 時使用此電子郵件位址。example.com 位址是專門用於文件 (RFC 2606) 的保留網域名稱。請勿使用隨機電子郵件 - 最好完全不提供電子郵件。自 2010 年 6 月 1 日起,電子郵件參數已強制執行。在過度使用的情况下,NCBI 會嘗試在阻止存取 E-utilities 之前,使用提供的電子郵件位址聯絡使用者。

  • 如果您在某些較大的軟體套件中使用 Biopython,請使用 tool 參數來指定它。您可以明確地將工具名稱設定為每次呼叫 Entrez 的參數(例如,在引數清單中包含 tool="MyLocalScript"),或者您可以設定全域工具名稱

    >>> from Bio import Entrez
    >>> Entrez.tool = "MyLocalScript"
    

    工具參數的預設值為 Biopython。

  • 對於大型查詢,NCBI 也建議使用其會話歷程記錄功能(WebEnv 會話 Cookie 字串,請參閱 使用歷史和 WebEnv 章節)。這只稍微複雜一點。

總而言之,請合理地使用您的使用量。如果您計劃下載大量資料,請考慮其他選項。例如,如果您想要輕鬆存取所有人類基因,請考慮透過 FTP 以 GenBank 檔案的形式提取每個染色體,並將其匯入您自己的 BioSQL 資料庫(請參閱 BioSQL – 將序列儲存在關聯式資料庫中 章節)。

EInfo:取得 Entrez 資料庫的相關資訊

EInfo 提供 NCBI 每個資料庫的欄位索引詞計數、上次更新和可用連結。此外,您可以使用 EInfo 取得透過 Entrez 工具可存取的所有資料庫名稱列表

>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> stream = Entrez.einfo()
>>> result = stream.read()
>>> stream.close()

變數 result 現在包含 XML 格式的資料庫列表

>>> print(result)
<?xml version="1.0"?>
<!DOCTYPE eInfoResult PUBLIC "-//NLM//DTD eInfoResult, 11 May 2002//EN"
 "https://www.ncbi.nlm.nih.gov/entrez/query/DTD/eInfo_020511.dtd">
<eInfoResult>
<DbList>
        <DbName>pubmed</DbName>
        <DbName>protein</DbName>
        <DbName>nucleotide</DbName>
        <DbName>nuccore</DbName>
        <DbName>nucgss</DbName>
        <DbName>nucest</DbName>
        <DbName>structure</DbName>
        <DbName>genome</DbName>
        <DbName>books</DbName>
        <DbName>cancerchromosomes</DbName>
        <DbName>cdd</DbName>
        <DbName>gap</DbName>
        <DbName>domains</DbName>
        <DbName>gene</DbName>
        <DbName>genomeprj</DbName>
        <DbName>gensat</DbName>
        <DbName>geo</DbName>
        <DbName>gds</DbName>
        <DbName>homologene</DbName>
        <DbName>journals</DbName>
        <DbName>mesh</DbName>
        <DbName>ncbisearch</DbName>
        <DbName>nlmcatalog</DbName>
        <DbName>omia</DbName>
        <DbName>omim</DbName>
        <DbName>pmc</DbName>
        <DbName>popset</DbName>
        <DbName>probe</DbName>
        <DbName>proteinclusters</DbName>
        <DbName>pcassay</DbName>
        <DbName>pccompound</DbName>
        <DbName>pcsubstance</DbName>
        <DbName>snp</DbName>
        <DbName>taxonomy</DbName>
        <DbName>toolkit</DbName>
        <DbName>unigene</DbName>
        <DbName>unists</DbName>
</DbList>
</eInfoResult>

由於這是一個相當簡單的 XML 檔案,我們可以簡單地透過字串搜尋來提取它包含的資訊。但如果使用 Bio.Entrez 的解析器,我們可以將這個 XML 檔案直接解析成 Python 物件。

>>> from Bio import Entrez
>>> stream = Entrez.einfo()
>>> record = Entrez.read(stream)

現在,record 是一個只有一個鍵的字典。

>>> record.keys()
dict_keys(['DbList'])

這個鍵所儲存的值是上面 XML 中顯示的資料庫名稱列表。

>>> record["DbList"]
['pubmed', 'protein', 'nucleotide', 'nuccore', 'nucgss', 'nucest',
 'structure', 'genome', 'books', 'cancerchromosomes', 'cdd', 'gap',
 'domains', 'gene', 'genomeprj', 'gensat', 'geo', 'gds', 'homologene',
 'journals', 'mesh', 'ncbisearch', 'nlmcatalog', 'omia', 'omim', 'pmc',
 'popset', 'probe', 'proteinclusters', 'pcassay', 'pccompound',
 'pcsubstance', 'snp', 'taxonomy', 'toolkit', 'unigene', 'unists']

對於這些資料庫中的每一個,我們可以再次使用 EInfo 來獲得更多資訊。

>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> stream = Entrez.einfo(db="pubmed")
>>> record = Entrez.read(stream)
>>> record["DbInfo"]["Description"]
'PubMed bibliographic record'
>>> record["DbInfo"]["Count"]
'17989604'
>>> record["DbInfo"]["LastUpdate"]
'2008/05/24 06:45'

試試看 record["DbInfo"].keys() 來查看此記錄中儲存的其他資訊。其中最有用的之一是可用於 ESearch 的可能搜尋欄位列表。

>>> for field in record["DbInfo"]["FieldList"]:
...     print("%(Name)s, %(FullName)s, %(Description)s" % field)
...
ALL, All Fields, All terms from all searchable fields
UID, UID, Unique number assigned to publication
FILT, Filter, Limits the records
TITL, Title, Words in title of publication
WORD, Text Word, Free text associated with publication
MESH, MeSH Terms, Medical Subject Headings assigned to publication
MAJR, MeSH Major Topic, MeSH terms of major importance to publication
AUTH, Author, Author(s) of publication
JOUR, Journal, Journal abbreviation of publication
AFFL, Affiliation, Author's institutional affiliation and address
...

這是一個很長的列表,但間接地告訴你,對於 PubMed 資料庫,你可以執行類似 Jones[AUTH] 來搜尋作者欄位,或 Sanger[AFFL] 來限制在 Sanger 中心作者的搜尋。這會非常方便,特別是當您不太熟悉特定資料庫時。

ESearch:搜尋 Entrez 資料庫

要搜尋任何這些資料庫,我們使用 Bio.Entrez.esearch()。例如,我們在 PubMed 中搜尋標題包含 Biopython 的出版物。

>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> stream = Entrez.esearch(db="pubmed", term="biopython[title]", retmax="40")
>>> record = Entrez.read(stream)
>>> "19304878" in record["IdList"]
True
>>> print(record["IdList"])
['22909249', '19304878']

在這個輸出中,你會看到 PubMed ID(包括 19304878,這是 Biopython 應用說明的 PMID),這些 ID 可以透過 EFetch 檢索(請參閱 EFetch:從 Entrez 下載完整記錄 章節)。

你也可以使用 ESearch 來搜尋 GenBank。這裡我們快速搜尋 Cypripedioideae 蘭花中的 matK 基因(請參閱 EInfo:取得有關 Entrez 資料庫的資訊 章節,了解如何找出您可以在每個 Entrez 資料庫中搜尋的欄位)。

>>> stream = Entrez.esearch(
...     db="nucleotide", term="Cypripedioideae[Orgn] AND matK[Gene]", idtype="acc"
... )
>>> record = Entrez.read(stream)
>>> record["Count"]
'348'
>>> record["IdList"]
['JQ660909.1', 'JQ660908.1', 'JQ660907.1', 'JQ660906.1', ..., 'JQ660890.1']

每個 ID(JQ660909.1、JQ660908.1、JQ660907.1...)都是一個 GenBank 識別碼(登錄號)。請參閱 EFetch:從 Entrez 下載完整記錄 章節,了解如何實際下載這些 GenBank 記錄。

請注意,您可以使用 NCBI 分類識別碼來限制搜尋,而不是使用像 Cypripedioideae[Orgn] 這樣的物種名稱,這裡會是 txid158330[Orgn]。這目前沒有在 ESearch 幫助頁面中記錄,NCBI 在回覆電子郵件查詢時解釋了這一點。您可以透過操作 Entrez 網頁介面來推斷搜尋詞的格式。例如,在基因組搜尋中加入 complete[prop] 會將搜尋限制為僅限已完成的基因組。

作為最後一個範例,讓我們取得計算期刊標題的列表。

>>> stream = Entrez.esearch(db="nlmcatalog", term="computational[Journal]", retmax="20")
>>> record = Entrez.read(stream)
>>> print("{} computational journals found".format(record["Count"]))
117 computational Journals found
>>> print("The first 20 are\n{}".format(record["IdList"]))
['101660833', '101664671', '101661657', '101659814', '101657941',
 '101653734', '101669877', '101649614', '101647835', '101639023',
 '101627224', '101647801', '101589678', '101585369', '101645372',
 '101586429', '101582229', '101574747', '101564639', '101671907']

同樣地,我們可以再次使用 EFetch 來取得這些期刊 ID 中每一個的更多資訊。

ESearch 有許多實用的選項 — 請參閱 ESearch 幫助頁面 了解更多資訊。

EPost:上傳識別碼列表

EPost 上傳 UI 列表以用於後續的搜尋策略;請參閱 EPost 幫助頁面 了解更多資訊。它可以透過 Biopython 中的 Bio.Entrez.epost() 函式取得。

舉例說明這在什麼時候有用,假設您有一個很長的 ID 列表想要使用 EFetch 下載(可能是序列、可能是引文 – 任何東西)。當您使用 EFetch 發出請求時,您的 ID 列表、資料庫等都會轉換為傳送到伺服器的長 URL。如果您的 ID 列表很長,這個 URL 就會變得很長,而長 URL 可能會中斷(例如,某些代理伺服器無法很好地處理)。

相反地,您可以將其分成兩個步驟,首先使用 EPost 上傳 ID 列表(這在內部使用「HTML post」,而不是「HTML get」,以解決長 URL 的問題)。透過歷史記錄的支援,您就可以參考這個長 ID 列表,並使用 EFetch 下載相關的資料。

讓我們來看一個簡單的例子,了解 EPost 如何運作 – 上傳一些 PubMed 識別碼。

>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> id_list = ["19304878", "18606172", "16403221", "16377612", "14871861", "14630660"]
>>> print(Entrez.epost("pubmed", id=",".join(id_list)).read())
<?xml version="1.0"?>
<!DOCTYPE ePostResult PUBLIC "-//NLM//DTD ePostResult, 11 May 2002//EN"
 "https://www.ncbi.nlm.nih.gov/entrez/query/DTD/ePost_020511.dtd">
<ePostResult>
    <QueryKey>1</QueryKey>
    <WebEnv>NCID_01_206841095_130.14.22.101_9001_1242061629</WebEnv>
</ePostResult>

返回的 XML 包含兩個重要的字串,QueryKeyWebEnv,它們共同定義您的歷史記錄會話。您會提取這些值以用於另一個 Entrez 呼叫(例如 EFetch)。

>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> id_list = ["19304878", "18606172", "16403221", "16377612", "14871861", "14630660"]
>>> search_results = Entrez.read(Entrez.epost("pubmed", id=",".join(id_list)))
>>> webenv = search_results["WebEnv"]
>>> query_key = search_results["QueryKey"]

使用歷史記錄和 WebEnv 節說明如何使用歷史記錄功能。

ESummary:從主要 ID 檢索摘要

ESummary 從主要 ID 列表檢索文件摘要(請參閱 ESummary 幫助頁面 了解更多資訊)。在 Biopython 中,ESummary 可用作 Bio.Entrez.esummary()。以上面的搜尋結果為例,我們可以找到有關 ID 為 30367 的期刊的更多資訊。

>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> stream = Entrez.esummary(db="nlmcatalog", id="101660833")
>>> record = Entrez.read(stream)
>>> info = record[0]["TitleMainList"][0]
>>> print("Journal info\nid: {}\nTitle: {}".format(record[0]["Id"], info["Title"]))
Journal info
id: 101660833
Title: IEEE transactions on computational imaging.

EFetch:從 Entrez 下載完整記錄

當您想要從 Entrez 檢索完整記錄時,您會使用 EFetch。這涵蓋了幾個可能的資料庫,如主要 EFetch 幫助頁面 上所述。

對於它們的大多數資料庫,NCBI 支援幾種不同的檔案格式。使用 Bio.Entrez.efetch() 從 Entrez 請求特定檔案格式需要指定 rettype 和/或 retmode 選用參數。不同的組合在 NCBI efetch 網頁 上連結的每個資料庫類型頁面中都有說明。

一個常見的用法是以 FASTA 或 GenBank/GenPept 純文字格式下載序列(然後可以使用 Bio.SeqIO 進行解析,請參閱 從網路解析 GenBank 記錄EFetch:從 Entrez 下載完整記錄 章節)。從上面的 Cypripedioideae 範例中,我們可以使用 Bio.Entrez.efetch 下載 GenBank 記錄 EU490707。

>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> stream = Entrez.efetch(db="nucleotide", id="EU490707", rettype="gb", retmode="text")
>>> print(stream.read())
LOCUS       EU490707                1302 bp    DNA     linear   PLN 26-JUL-2016
DEFINITION  Selenipedium aequinoctiale maturase K (matK) gene, partial cds;
            chloroplast.
ACCESSION   EU490707
VERSION     EU490707.1
KEYWORDS    .
SOURCE      chloroplast Selenipedium aequinoctiale
  ORGANISM  Selenipedium aequinoctiale
            Eukaryota; Viridiplantae; Streptophyta; Embryophyta; Tracheophyta;
            Spermatophyta; Magnoliopsida; Liliopsida; Asparagales; Orchidaceae;
            Cypripedioideae; Selenipedium.
REFERENCE   1  (bases 1 to 1302)
  AUTHORS   Neubig,K.M., Whitten,W.M., Carlsward,B.S., Blanco,M.A., Endara,L.,
            Williams,N.H. and Moore,M.
  TITLE     Phylogenetic utility of ycf1 in orchids: a plastid gene more
            variable than matK
  JOURNAL   Plant Syst. Evol. 277 (1-2), 75-84 (2009)
REFERENCE   2  (bases 1 to 1302)
  AUTHORS   Neubig,K.M., Whitten,W.M., Carlsward,B.S., Blanco,M.A.,
            Endara,C.L., Williams,N.H. and Moore,M.J.
  TITLE     Direct Submission
  JOURNAL   Submitted (14-FEB-2008) Department of Botany, University of
            Florida, 220 Bartram Hall, Gainesville, FL 32611-8526, USA
FEATURES             Location/Qualifiers
     source          1..1302
                     /organism="Selenipedium aequinoctiale"
                     /organelle="plastid:chloroplast"
                     /mol_type="genomic DNA"
                     /specimen_voucher="FLAS:Blanco 2475"
                     /db_xref="taxon:256374"
     gene            <1..>1302
                     /gene="matK"
     CDS             <1..>1302
                     /gene="matK"
                     /codon_start=1
                     /transl_table=11
                     /product="maturase K"
                     /protein_id="ACC99456.1"
                     /translation="IFYEPVEIFGYDNKSSLVLVKRLITRMYQQNFLISSVNDSNQKG
                     FWGHKHFFSSHFSSQMVSEGFGVILEIPFSSQLVSSLEEKKIPKYQNLRSIHSIFPFL
                     EDKFLHLNYVSDLLIPHPIHLEILVQILQCRIKDVPSLHLLRLLFHEYHNLNSLITSK
                     KFIYAFSKRKKRFLWLLYNSYVYECEYLFQFLRKQSSYLRSTSSGVFLERTHLYVKIE
                     HLLVVCCNSFQRILCFLKDPFMHYVRYQGKAILASKGTLILMKKWKFHLVNFWQSYFH
                     FWSQPYRIHIKQLSNYSFSFLGYFSSVLENHLVVRNQMLENSFIINLLTKKFDTIAPV
                     ISLIGSLSKAQFCTVLGHPISKPIWTDFSDSDILDRFCRICRNLCRYHSGSSKKQVLY
                     RIKYILRLSCARTLARKHKSTVRTFMRRLGSGLLEEFFMEEE"
ORIGIN
        1 attttttacg aacctgtgga aatttttggt tatgacaata aatctagttt agtacttgtg
       61 aaacgtttaa ttactcgaat gtatcaacag aattttttga tttcttcggt taatgattct
      121 aaccaaaaag gattttgggg gcacaagcat tttttttctt ctcatttttc ttctcaaatg
      181 gtatcagaag gttttggagt cattctggaa attccattct cgtcgcaatt agtatcttct
      241 cttgaagaaa aaaaaatacc aaaatatcag aatttacgat ctattcattc aatatttccc
      301 tttttagaag acaaattttt acatttgaat tatgtgtcag atctactaat accccatccc
      361 atccatctgg aaatcttggt tcaaatcctt caatgccgga tcaaggatgt tccttctttg
      421 catttattgc gattgctttt ccacgaatat cataatttga atagtctcat tacttcaaag
      481 aaattcattt acgccttttc aaaaagaaag aaaagattcc tttggttact atataattct
      541 tatgtatatg aatgcgaata tctattccag tttcttcgta aacagtcttc ttatttacga
      601 tcaacatctt ctggagtctt tcttgagcga acacatttat atgtaaaaat agaacatctt
      661 ctagtagtgt gttgtaattc ttttcagagg atcctatgct ttctcaagga tcctttcatg
      721 cattatgttc gatatcaagg aaaagcaatt ctggcttcaa agggaactct tattctgatg
      781 aagaaatgga aatttcatct tgtgaatttt tggcaatctt attttcactt ttggtctcaa
      841 ccgtatagga ttcatataaa gcaattatcc aactattcct tctcttttct ggggtatttt
      901 tcaagtgtac tagaaaatca tttggtagta agaaatcaaa tgctagagaa ttcatttata
      961 ataaatcttc tgactaagaa attcgatacc atagccccag ttatttctct tattggatca
     1021 ttgtcgaaag ctcaattttg tactgtattg ggtcatccta ttagtaaacc gatctggacc
     1081 gatttctcgg attctgatat tcttgatcga ttttgccgga tatgtagaaa tctttgtcgt
     1141 tatcacagcg gatcctcaaa aaaacaggtt ttgtatcgta taaaatatat acttcgactt
     1201 tcgtgtgcta gaactttggc acggaaacat aaaagtacag tacgcacttt tatgcgaaga
     1261 ttaggttcgg gattattaga agaattcttt atggaagaag aa
//

請注意,截至 2016 年 10 月,GI 識別碼已停用,改用登錄號。您仍然可以根據它們的 GI 提取序列,但新的序列不再給予此識別碼。您應該改為使用範例中完成的「登錄號」來參考它們。

參數 rettype="gb"retmode="text" 讓我們以 GenBank 格式下載此記錄。

請注意,直到 2009 年復活節,Entrez EFetch API 允許您使用 "genbank" 作為返回類型,但是 NCBI 現在堅持使用官方的返回類型 "gb" 或 "gbwithparts"(或蛋白質的 "gp"),如線上所述。另請注意,直到 2012 年 2 月,Entrez EFetch API 會預設返回純文字檔案,但現在預設為 XML。

或者,您可以例如使用 rettype="fasta" 來取得 Fasta 格式;請參閱 EFetch 序列幫助頁面 了解其他選項。請記住,可用的格式取決於您從哪個資料庫下載 – 請參閱主要的 EFetch 幫助頁面

如果您以 Bio.SeqIO 接受的格式之一提取記錄(請參閱 序列輸入/輸出 章節),您可以將其直接解析為 SeqRecord

>>> from Bio import SeqIO
>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> stream = Entrez.efetch(db="nucleotide", id="EU490707", rettype="gb", retmode="text")
>>> record = SeqIO.read(stream, "genbank")
>>> stream.close()
>>> print(record.id)
EU490707.1
>>> print(record.name)
EU490707
>>> print(record.description)
Selenipedium aequinoctiale maturase K (matK) gene, partial cds; chloroplast
>>> print(len(record.features))
3
>>> record.seq
Seq('ATTTTTTACGAACCTGTGGAAATTTTTGGTTATGACAATAAATCTAGTTTAGTA...GAA')

請注意,更典型的用法是將序列資料儲存到本機檔案,然後使用 Bio.SeqIO 進行解析。這可以省去您在處理腳本時重複下載相同檔案的麻煩,並減少 NCBI 伺服器的負載。例如

import os
from Bio import SeqIO
from Bio import Entrez

Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
filename = "EU490707.gbk"
if not os.path.isfile(filename):
    # Downloading...
    stream = Entrez.efetch(db="nucleotide", id="EU490707", rettype="gb", retmode="text")
    output = open(filename, "w")
    output.write(streame.read())
    output.close()
    stream.close()
    print("Saved")

print("Parsing...")
record = SeqIO.read(filename, "genbank")
print(record)

要以 XML 格式取得輸出,您可以使用 Bio.Entrez.read() 函式進行解析,請使用 retmode="xml"

>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> stream = Entrez.efetch(db="nucleotide", id="EU490707", retmode="xml")
>>> record = Entrez.read(stream)
>>> stream.close()
>>> record[0]["GBSeq_definition"]
'Selenipedium aequinoctiale maturase K (matK) gene, partial cds; chloroplast'
>>> record[0]["GBSeq_source"]
'chloroplast Selenipedium aequinoctiale'

所以,以上處理了序列。有關解析其他資料庫特定檔案格式(例如 PubMed 中使用的 MEDLINE 格式)的範例,請參閱 專用解析器 章節。

如果您想要使用 Bio.Entrez.esearch() 執行搜尋,然後使用 Bio.Entrez.efetch() 下載記錄,則應使用 WebEnv 歷史記錄功能 – 請參閱 使用歷史記錄和 WebEnv 章節。

EGQuery: 全域查詢 - 搜尋詞的計數

EGQuery 提供每個 Entrez 資料庫中搜尋詞的計數(即全域查詢)。這對於找出您的搜尋詞在每個資料庫中會找到多少項目,而無需實際使用 ESearch 進行多次單獨搜尋(請參閱下面的搜尋、下載和解析 Entrez 核苷酸記錄中的範例)特別有用。

在這個範例中,我們使用 Bio.Entrez.egquery() 來取得 "Biopython" 的計數。

>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> stream = Entrez.egquery(term="biopython")
>>> record = Entrez.read(stream)
>>> for row in record["eGQueryResult"]:
...     print(row["DbName"], row["Count"])
...
pubmed 6
pmc 62
journals 0
...

有關更多資訊,請參閱EGQuery 說明頁面

ESpell: 取得拼寫建議

ESpell 擷取拼寫建議。在這個範例中,我們使用 Bio.Entrez.espell() 來取得 Biopython 的正確拼寫。

>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> stream = Entrez.espell(term="biopythooon")
>>> record = Entrez.read(stream)
>>> record["Query"]
'biopythooon'
>>> record["CorrectedQuery"]
'biopython'

有關更多資訊,請參閱ESpell 說明頁面。此功能的主要用途是為 GUI 工具提供搜尋詞的自動建議。

解析龐大的 Entrez XML 檔案

Entrez.read 函式會將 Entrez 傳回的整個 XML 檔案讀取到單一 Python 物件中,並保留在記憶體中。若要解析過大而無法放入記憶體的 Entrez XML 檔案,您可以使用函式 Entrez.parse。這是一個產生器函式,會逐一讀取 XML 檔案中的記錄。只有當 XML 檔案反映 Python 列表物件時,此函式才有用 (換句話說,如果具有無限記憶體資源的電腦上的 Entrez.read 會傳回 Python 列表)。

例如,您可以從 NCBI 的 ftp 站點下載特定生物的整個 Entrez Gene 資料庫的檔案。這些檔案可能非常大。例如,在 2009 年 9 月 4 日,包含人類 Entrez Gene 資料庫的檔案 Homo_sapiens.ags.gz 的大小為 116576 kB。可以使用 NCBI 的 gene2xml 程式將此 ASN 格式的檔案轉換為 XML 檔案 (有關更多資訊,請參閱 NCBI 的 ftp 站點)。

$ gene2xml -b T -i Homo_sapiens.ags -o Homo_sapiens.xml

產生的 XML 檔案大小為 6.1 GB。嘗試在此檔案上執行 Entrez.read 會在許多電腦上導致 MemoryError

XML 檔案 Homo_sapiens.xml 包含一個 Entrez 基因記錄的列表,每個記錄對應人類中的一個 Entrez 基因。Entrez.parse 會逐一擷取這些基因記錄。然後,您可以藉由反覆運算記錄來印出或儲存每個記錄中的相關資訊。例如,此腳本會反覆運算 Entrez 基因記錄,並印出所有目前基因的基因編號和名稱。

>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> stream = open("Homo_sapiens.xml", "rb")
>>> records = Entrez.parse(stream)

或者,您可以使用

>>> records = Entrez.parse("Homo_sapiens.xml")

並讓 Bio.Entrez 處理開啟和關閉檔案。這樣比較安全,因為檔案會在解析後自動關閉,或在發生錯誤時關閉。

>>> for record in records:
...     status = record["Entrezgene_track-info"]["Gene-track"]["Gene-track_status"]
...     if status.attributes["value"] == "discontinued":
...         continue
...     geneid = record["Entrezgene_track-info"]["Gene-track"]["Gene-track_geneid"]
...     genename = record["Entrezgene_gene"]["Gene-ref"]["Gene-ref_locus"]
...     print(geneid, genename)
...
1 A1BG
2 A2M
3 A2MP
8 AA
9 NAT1
10 NAT2
11 AACP
12 SERPINA3
13 AADAC
14 AAMP
15 AANAT
16 AARS
17 AAVS1
...

HTML 跳脫字元

Pubmed 記錄可能包含 HTML 標籤來指示,例如,下標、上標或斜體文字,以及透過 MathML 表示的數學符號。預設情況下,Bio.Entrez 解析器會將所有文字視為不含標記的純文字;例如,Pubmed 記錄摘要中的片段 “\(P < 0.05\)”,它在 Entrez 傳回的 XML 中編碼為

<i>P</i> &lt; 0.05

,會被 Bio.Entrez 解析器轉換為 Python 字串

'<i>P</i> < 0.05'

雖然這樣更具可讀性,但由於小於符號,它不是有效的 HTML,而且使得後續使用 HTML 解析器處理文字變得不切實際。為了確保解析器傳回的所有字串都是有效的 HTML,請在呼叫 Entrez.readEntrez.parse 時,將 escape 引數設為 True

>>> record = Entrez.read(stream, escape=True)

然後,解析器會將所有 HTML 中不允許的字元替換為其 HTML 跳脫字元對應項;在上面的範例中,解析器將產生

'<i>P</i> &lt; 0.05'

,這是一個有效的 HTML 片段。預設情況下,escapeFalse

處理錯誤

該檔案不是 XML 檔案

例如,如果您嘗試將 Fasta 檔案解析為 XML 檔案,就會發生此錯誤。

>>> from Bio import Entrez
>>> stream = open("NC_005816.fna", "rb")  # a Fasta file
>>> record = Entrez.read(stream)
Traceback (most recent call last):
  ...
Bio.Entrez.Parser.NotXMLError: Failed to parse the XML data (syntax error: line 1, column 0). Please make sure that the input data are in XML format.

在這裡,解析器沒有找到 XML 檔案應該開頭的 <?xml ... 標籤,因此(正確地)判斷該檔案不是 XML 檔案。

檔案過早結束或以其他方式損毀

當您的檔案為 XML 格式但已損毀(例如,過早結束)時,解析器會引發 CorruptedXMLError。

以下是過早結束的 XML 檔案範例

<?xml version="1.0"?>
<!DOCTYPE eInfoResult PUBLIC "-//NLM//DTD eInfoResult, 11 May 2002//EN" "https://www.ncbi.nlm.nih.gov/entrez/query/DTD/eInfo_020511.dtd">
<eInfoResult>
<DbList>
        <DbName>pubmed</DbName>
        <DbName>protein</DbName>
        <DbName>nucleotide</DbName>
        <DbName>nuccore</DbName>
        <DbName>nucgss</DbName>
        <DbName>nucest</DbName>
        <DbName>structure</DbName>
        <DbName>genome</DbName>
        <DbName>books</DbName>
        <DbName>cancerchromosomes</DbName>
        <DbName>cdd</DbName>

,這會產生以下回溯

>>> Entrez.read(stream)
Traceback (most recent call last):
  ...
Bio.Entrez.Parser.CorruptedXMLError: Failed to parse the XML data (no element found: line 16, column 0). Please make sure that the input data are not corrupted.

請注意,錯誤訊息會告訴您在 XML 檔案中的哪個位置偵測到錯誤。

檔案包含關聯 DTD 中遺失的項目

以下是一個 XML 檔案的範例,其中包含在對應的 DTD 檔案中沒有描述的標籤。

<?xml version="1.0"?>
<!DOCTYPE eInfoResult PUBLIC "-//NLM//DTD eInfoResult, 11 May 2002//EN" "https://www.ncbi.nlm.nih.gov/entrez/query/DTD/eInfo_020511.dtd">
<eInfoResult>
        <DbInfo>
        <DbName>pubmed</DbName>
        <MenuName>PubMed</MenuName>
        <Description>PubMed bibliographic record</Description>
        <Count>20161961</Count>
        <LastUpdate>2010/09/10 04:52</LastUpdate>
        <FieldList>
                <Field>
...
                </Field>
        </FieldList>
        <DocsumList>
                <Docsum>
                        <DsName>PubDate</DsName>
                        <DsType>4</DsType>
                        <DsTypeName>string</DsTypeName>
                </Docsum>
                <Docsum>
                        <DsName>EPubDate</DsName>
...
        </DbInfo>
</eInfoResult>

在此檔案中,由於某些原因,標籤 <DocsumList> (以及其他幾個標籤) 未在 DTD 檔案 eInfo_020511.dtd 中列出,該檔案在第二行中指定為此 XML 檔案的 DTD。預設情況下,如果解析器無法在 DTD 中找到某些標籤,則會停止並引發 ValidationError。

>>> from Bio import Entrez
>>> stream = open("einfo3.xml", "rb")
>>> record = Entrez.read(stream)
Traceback (most recent call last):
  ...
Bio.Entrez.Parser.ValidationError: Failed to find tag 'DocsumList' in the DTD. To skip all tags that are not represented in the DTD, please call Bio.Entrez.read or Bio.Entrez.parse with validate=False.

或者,您可以指示解析器跳過此類標籤,而不是引發 ValidationError。這是透過呼叫 Entrez.readEntrez.parse 時,將引數 validate 設為 False 來完成的。

>>> from Bio import Entrez
>>> stream = open("einfo3.xml", "rb")
>>> record = Entrez.read(stream, validate=False)
>>> stream.close()

當然,不在 DTD 中的 XML 標籤中包含的資訊不會出現在 Entrez.read 傳回的記錄中。

檔案包含錯誤訊息

例如,當您嘗試存取不存在的 PubMed ID 的 PubMed 記錄時,可能會發生這種情況。預設情況下,這會引發 RuntimeError

>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> stream = Entrez.esummary(db="pubmed", id="99999999")
>>> record = Entrez.read(stream)
Traceback (most recent call last):
...
RuntimeError: UID=99999999: cannot get document summary

如果您正在存取多個 PubMed 記錄,如果其中一個 PubMed ID 不正確,則 RuntimeError 會阻止您接收任何 PubMed 記錄的結果。為了規避這一點,您可以將 ignore_errors 引數設為 True。這會傳回有效 PubMed ID 的請求結果,並為不正確的 ID 傳回 ErrorElement

>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> stream = Entrez.esummary(db="pubmed", id="19304878,99999999,31278684")
>>> record = Entrez.read(stream, ignore_errors=True)
>>> len(record)
3
>>> record[0].tag
'DocSum'
>>> record[0]["Title"]
'Biopython: freely available Python tools for computational molecular biology and bioinformatics.'
>>> record[1].tag
'ERROR'
>>> record[1]
ErrorElement('UID=99999999: cannot get document summary')
>>> record[2].tag
'DocSum'
>>> record[2]["Title"]
'Sharing Programming Resources Between Bio* Projects.'

專用解析器

Bio.Entrez.read() 函式可以解析 Entrez 傳回的大部分(如果不是全部)XML 輸出。Entrez 通常允許您以其他格式擷取記錄,這些格式在可讀性(或下載大小)方面可能比 XML 格式具有一些優勢。

若要使用 Bio.Entrez.efetch() 從 Entrez 請求特定檔案格式,需要指定 rettype 和/或 retmode 選用參數。在 NCBI efetch 網頁上,針對每個資料庫類型描述了不同的組合。

一個顯而易見的例子是,您可能偏好下載 FASTA 或 GenBank/GenPept 純文字格式的序列(然後可以使用 Bio.SeqIO 進行解析,請參閱 從網路解析 GenBank 記錄EFetch:從 Entrez 下載完整記錄章節)。對於文獻資料庫,Biopython 包含用於解析 PubMed 中使用的 MEDLINE 格式的解析器。

解析 Medline 記錄

您可以在 Bio.Medline 中找到 Medline 解析器。假設我們要解析包含一個 Medline 記錄的檔案 pubmed_result1.txt。您可以在 Biopython 的 Tests\Medline 目錄中找到此檔案。該檔案看起來像這樣:

PMID- 12230038
OWN - NLM
STAT- MEDLINE
DA  - 20020916
DCOM- 20030606
LR  - 20041117
PUBM- Print
IS  - 1467-5463 (Print)
VI  - 3
IP  - 3
DP  - 2002 Sep
TI  - The Bio* toolkits--a brief overview.
PG  - 296-302
AB  - Bioinformatics research is often difficult to do with commercial software. The
      Open Source BioPerl, BioPython and Biojava projects provide toolkits with
...

我們首先開啟檔案,然後進行解析

>>> from Bio import Medline
>>> with open("pubmed_result1.txt") as stream:
...     record = Medline.read(stream)
...

record 現在以 Python 字典的形式包含 Medline 記錄

>>> record["PMID"]
'12230038'
>>> record["AB"]
'Bioinformatics research is often difficult to do with commercial software.
The Open Source BioPerl, BioPython and Biojava projects provide toolkits with
multiple functionality that make it easier to create customized pipelines or
analysis. This review briefly compares the quirks of the underlying languages
and the functionality, documentation, utility and relative advantages of the
Bio counterparts, particularly from the point of view of the beginning
biologist programmer.'

Medline 記錄中使用的鍵名可能相當晦澀難懂;請使用

>>> help(record)

來獲得簡短的摘要。

若要解析包含多個 Medline 記錄的檔案,您可以使用 parse 函數來代替

>>> from Bio import Medline
>>> with open("pubmed_result2.txt") as stream:
...     for record in Medline.parse(stream):
...         print(record["TI"])
...
A high level interface to SCOP and ASTRAL implemented in python.
GenomeDiagram: a python package for the visualization of large-scale genomic data.
Open source clustering software.
PDB file parser and structure class implemented in Python.

除了解析儲存在檔案中的 Medline 記錄之外,您還可以解析由 Bio.Entrez.efetch 下載的 Medline 記錄。例如,讓我們查看 PubMed 中與 Biopython 相關的所有 Medline 記錄

>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> stream = Entrez.esearch(db="pubmed", term="biopython")
>>> record = Entrez.read(stream)
>>> record["IdList"]
['19304878', '18606172', '16403221', '16377612', '14871861', '14630660', '12230038']

現在我們使用 Bio.Entrez.efetch 來下載這些 Medline 記錄

>>> idlist = record["IdList"]
>>> stream = Entrez.efetch(db="pubmed", id=idlist, rettype="medline", retmode="text")

在這裡,我們指定 rettype="medline"retmode="text" 以取得純文字 Medline 格式的 Medline 記錄。現在我們使用 Bio.Medline 來解析這些記錄

>>> from Bio import Medline
>>> records = Medline.parse(stream)
>>> for record in records:
...     print(record["AU"])
...
['Cock PJ', 'Antao T', 'Chang JT', 'Chapman BA', 'Cox CJ', 'Dalke A', ..., 'de Hoon MJ']
['Munteanu CR', 'Gonzalez-Diaz H', 'Magalhaes AL']
['Casbon JA', 'Crooks GE', 'Saqi MA']
['Pritchard L', 'White JA', 'Birch PR', 'Toth IK']
['de Hoon MJ', 'Imoto S', 'Nolan J', 'Miyano S']
['Hamelryck T', 'Manderick B']
['Mangalam H']

為了比較,這裡我們展示一個使用 XML 格式的範例

>>> stream = Entrez.efetch(db="pubmed", id=idlist, rettype="medline", retmode="xml")
>>> records = Entrez.read(stream)
>>> for record in records["PubmedArticle"]:
...     print(record["MedlineCitation"]["Article"]["ArticleTitle"])
...
Biopython: freely available Python tools for computational molecular biology and
 bioinformatics.
Enzymes/non-enzymes classification model complexity based on composition, sequence,
 3D and topological indices.
A high level interface to SCOP and ASTRAL implemented in python.
GenomeDiagram: a python package for the visualization of large-scale genomic data.
Open source clustering software.
PDB file parser and structure class implemented in Python.
The Bio* toolkits--a brief overview.

請注意,在這兩個範例中,為了簡單起見,我們天真地組合了 ESearch 和 EFetch。在這種情況下,NCBI 希望您使用他們的歷史記錄功能,如 使用歷史記錄和 WebEnv 章節所示。

解析 GEO 記錄

GEO ( Gene Expression Omnibus ) 是一個高通量基因表現和雜交陣列資料的資料儲存庫。Bio.Geo 模組可用於解析 GEO 格式的資料。

以下程式碼片段顯示如何將範例 GEO 檔案 GSE16.txt 解析為記錄並印出該記錄

>>> from Bio import Geo
>>> stream = open("GSE16.txt")
>>> records = Geo.parse(stream)
>>> for record in records:
...     print(record)
...

您可以使用 ESearch 搜尋「gds」資料庫(GEO 資料集)

>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> stream = Entrez.esearch(db="gds", term="GSE16")
>>> record = Entrez.read(stream)
>>> stream.close()
>>> record["Count"]
'27'
>>> record["IdList"]
['200000016', '100000028', ...]

從 Entrez 網站來看,UID「200000016」是 GDS16,而另一個命中「100000028」是相關的平台 GPL28。不幸的是,在撰寫本文時,NCBI 似乎不支援使用 Entrez 下載 GEO 檔案(既不是 XML 格式,也不是文字格式的簡單綜合格式 (SOFT) 格式)。

不過,實際上直接從 ftp://ftp.ncbi.nih.gov/pub/geo/ 使用 FTP 下載 GEO 檔案非常簡單。在這種情況下,您可能想要 ftp://ftp.ncbi.nih.gov/pub/geo/DATA/SOFT/by_series/GSE16/GSE16_family.soft.gz (壓縮檔案,請參閱 Python 模組 gzip)。

解析 UniGene 記錄

UniGene 是 NCBI 的轉錄組資料庫,每個 UniGene 記錄都顯示與特定生物體中特定基因相關的一組轉錄本。典型的 UniGene 記錄如下所示:

ID          Hs.2
TITLE       N-acetyltransferase 2 (arylamine N-acetyltransferase)
GENE        NAT2
CYTOBAND    8p22
GENE_ID     10
LOCUSLINK   10
HOMOL       YES
EXPRESS      bone| connective tissue| intestine| liver| liver tumor| normal| soft tissue/muscle tissue tumor| adult
RESTR_EXPR   adult
CHROMOSOME  8
STS         ACC=PMC310725P3 UNISTS=272646
STS         ACC=WIAF-2120 UNISTS=44576
STS         ACC=G59899 UNISTS=137181
...
STS         ACC=GDB:187676 UNISTS=155563
PROTSIM     ORG=10090; PROTGI=6754794; PROTID=NP_035004.1; PCT=76.55; ALN=288
PROTSIM     ORG=9796; PROTGI=149742490; PROTID=XP_001487907.1; PCT=79.66; ALN=288
PROTSIM     ORG=9986; PROTGI=126722851; PROTID=NP_001075655.1; PCT=76.90; ALN=288
...
PROTSIM     ORG=9598; PROTGI=114619004; PROTID=XP_519631.2; PCT=98.28; ALN=288

SCOUNT      38
SEQUENCE    ACC=BC067218.1; NID=g45501306; PID=g45501307; SEQTYPE=mRNA
SEQUENCE    ACC=NM_000015.2; NID=g116295259; PID=g116295260; SEQTYPE=mRNA
SEQUENCE    ACC=D90042.1; NID=g219415; PID=g219416; SEQTYPE=mRNA
SEQUENCE    ACC=D90040.1; NID=g219411; PID=g219412; SEQTYPE=mRNA
SEQUENCE    ACC=BC015878.1; NID=g16198419; PID=g16198420; SEQTYPE=mRNA
SEQUENCE    ACC=CR407631.1; NID=g47115198; PID=g47115199; SEQTYPE=mRNA
SEQUENCE    ACC=BG569293.1; NID=g13576946; CLONE=IMAGE:4722596; END=5'; LID=6989; SEQTYPE=EST; TRACE=44157214
...
SEQUENCE    ACC=AU099534.1; NID=g13550663; CLONE=HSI08034; END=5'; LID=8800; SEQTYPE=EST
//

這個特定的記錄顯示了來自人類基因 NAT2(編碼 N-乙酰轉移酶)的轉錄本集合(顯示在 SEQUENCE 行中)。PROTSIM 行顯示與 NAT2 具有顯著相似性的蛋白質,而 STS 行則顯示基因體中對應的序列標記位點。

若要解析 UniGene 檔案,請使用 Bio.UniGene 模組

>>> from Bio import UniGene
>>> input = open("myunigenefile.data")
>>> record = UniGene.read(input)

UniGene.read 傳回的 record 是一個 Python 物件,其屬性對應於 UniGene 記錄中的欄位。例如,

>>> record.ID
"Hs.2"
>>> record.title
"N-acetyltransferase 2 (arylamine N-acetyltransferase)"

EXPRESSRESTR_EXPR 行儲存為 Python 字串清單

[
    "bone",
    "connective tissue",
    "intestine",
    "liver",
    "liver tumor",
    "normal",
    "soft tissue/muscle tissue tumor",
    "adult",
]

針對 STSPROTSIMSEQUENCE 行傳回特殊物件,將每行中顯示的鍵儲存為屬性

>>> record.sts[0].acc
'PMC310725P3'
>>> record.sts[0].unists
'272646'

對於 PROTSIMSEQUENCE 行也是如此。

若要解析包含多個 UniGene 記錄的檔案,請使用 Bio.UniGene 中的 parse 函數

>>> from Bio import UniGene
>>> input = open("unigenerecords.data")
>>> records = UniGene.parse(input)
>>> for record in records:
...     print(record.ID)
...

使用 Proxy

通常您不需要擔心使用 Proxy,但如果這是您網路上的問題,以下說明如何處理。在內部,Bio.Entrez 使用標準 Python 程式庫 urllib 來存取 NCBI 伺服器。這會檢查名為 http_proxy 的環境變數,以自動設定任何簡單的 Proxy。不幸的是,此模組不支援需要驗證的 Proxy 使用。

您可以選擇設定 http_proxy 環境變數一次(如何執行此操作取決於您的作業系統)。或者,您可以在 Python 腳本的開頭在 Python 中設定此變數,例如:

import os

os.environ["http_proxy"] = "http://proxyhost.example.com:8080"

如需更多詳細資訊,請參閱 urllib 文件

範例

PubMed 和 Medline

如果您在醫學領域工作或對人類議題感興趣(並且很多時候即使您不是!),PubMed (https://www.ncbi.nlm.nih.gov/PubMed/) 是各種好東西的絕佳來源。因此,與其他東西一樣,我們希望能夠從中獲取資訊並在 Python 腳本中使用。

在此範例中,我們將查詢 PubMed 中所有與蘭花相關的文章(請參閱 使用範例 章節了解我們的動機)。我們首先檢查有多少這樣的文章

>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> stream = Entrez.egquery(term="orchid")
>>> record = Entrez.read(stream)
>>> for row in record["eGQueryResult"]:
...     if row["DbName"] == "pubmed":
...         print(row["Count"])
...
463

現在我們使用 Bio.Entrez.efetch 函數來下載這 463 篇文章的 PubMed ID

>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> stream = Entrez.esearch(db="pubmed", term="orchid", retmax=463)
>>> record = Entrez.read(stream)
>>> stream.close()
>>> idlist = record["IdList"]

這會傳回一個 Python 清單,其中包含與蘭花相關的所有文章的 PubMed ID

>>> print(idlist)
['18680603', '18665331', '18661158', '18627489', '18627452', '18612381',
'18594007', '18591784', '18589523', '18579475', '18575811', '18575690',
...

現在我們已經有了它們,我們顯然想要取得對應的 Medline 記錄並從中提取資訊。在這裡,我們將以 Medline 純文字格式下載 Medline 記錄,並使用 Bio.Medline 模組來解析它們

>>> from Bio import Medline
>>> stream = Entrez.efetch(db="pubmed", id=idlist, rettype="medline", retmode="text")
>>> records = Medline.parse(stream)

注意 - 我們在這裡執行了單獨的搜尋和擷取,NCBI 更希望您在這種情況下利用他們的歷史記錄支援。請參閱 使用歷史記錄和 WebEnv 章節。

請記住,records 是一個迭代器,因此您只能迭代這些記錄一次。如果您想要儲存這些記錄,您可以將它們轉換為清單

>>> records = list(records)

現在讓我們迭代這些記錄,以印出有關每條記錄的一些資訊

>>> for record in records:
...     print("title:", record.get("TI", "?"))
...     print("authors:", record.get("AU", "?"))
...     print("source:", record.get("SO", "?"))
...     print("")
...

此範例的輸出看起來像這樣

title: Sex pheromone mimicry in the early spider orchid (ophrys sphegodes):
patterns of hydrocarbons as the key mechanism for pollination by sexual
deception [In Process Citation]
authors: ['Schiestl FP', 'Ayasse M', 'Paulus HF', 'Lofstedt C', 'Hansson BS',
'Ibarra F', 'Francke W']
source: J Comp Physiol [A] 2000 Jun;186(6):567-74

尤其值得注意的是作者清單,它會以標準 Python 清單的形式傳回。這使得使用標準 Python 工具進行操作和搜尋變得很容易。例如,我們可以遍歷一堆條目,並使用如下程式碼搜尋特定作者

>>> search_author = "Waits T"
>>> for record in records:
...     if not "AU" in record:
...         continue
...     if search_author in record["AU"]:
...         print("Author %s found: %s" % (search_author, record["SO"]))
...

希望本節能讓您了解 Entrez 和 Medline 介面的強大功能和彈性,以及它們如何結合使用。

搜尋、下載和解析 Entrez Nucleotide 記錄

在這裡,我們將展示一個執行遠端 Entrez 查詢的簡單範例。在解析範例的 使用範例 章節中,我們討論了使用 NCBI 的 Entrez 網站來搜尋 NCBI 核苷酸資料庫,以取得有關 Cypripedioideae(我們的朋友拖鞋蘭)的資訊。現在,我們將探討如何使用 Python 腳本自動執行該程序。在此範例中,我們將僅展示如何連線、取得結果和解析結果,而 Entrez 模組會完成所有工作。

首先,我們使用 EGQuery 來找出在實際下載之前將取得的結果數量。EGQuery 會告訴我們在每個資料庫中找到多少搜尋結果,但在本範例中,我們只對核苷酸感興趣

>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> stream = Entrez.egquery(term="Cypripedioideae")
>>> record = Entrez.read(stream)
>>> for row in record["eGQueryResult"]:
...     if row["DbName"] == "nuccore":
...         print(row["Count"])
...
4457

因此,我們預期會找到 4457 筆 Entrez Nucleotide 記錄(此數字從 2008 年的 814 筆記錄增加;未來可能會繼續增加)。如果您發現一些高得離譜的命中次數,您可能需要重新考慮是否真的要下載所有這些記錄,這將是我們的下一步。讓我們使用 retmax 參數將檢索的記錄最大數量限制為 2008 年可用的數量

>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> stream = Entrez.esearch(
...     db="nucleotide", term="Cypripedioideae", retmax=814, idtype="acc"
... )
>>> record = Entrez.read(stream)
>>> stream.close()

在這裡,record 是一個 Python 字典,其中包含搜尋結果和一些輔助資訊。僅供參考,讓我們看看此字典中儲存的內容

>>> print(record.keys())
['Count', 'RetMax', 'IdList', 'TranslationSet', 'RetStart', 'QueryTranslation']

首先,讓我們檢查找到多少結果

>>> print(record["Count"])
'4457'

您可能會預期這裡的數字是 814,也就是我們要求檢索的最大記錄數量。然而,Count 代表的是該搜尋可用的總記錄數,而不是實際檢索到的數量。檢索到的記錄儲存在 record['IdList'] 中,其中應該包含我們要求的總數量。

>>> len(record["IdList"])
814

讓我們看看前五個結果。

>>> record["IdList"][:5]
['KX265015.1', 'KX265014.1', 'KX265013.1', 'KX265012.1', 'KX265011.1']

我們可以透過 efetch 下載這些記錄。雖然您可以逐一下載這些記錄,但為了減輕 NCBI 伺服器的負擔,最好一次擷取多筆記錄,如下所示。然而,在這種情況下,您應該理想地使用稍後在「使用歷史記錄和 WebEnv」章節中描述的歷史記錄功能。

>>> idlist = ",".join(record["IdList"][:5])
>>> print(idlist)
KX265015.1, KX265014.1, KX265013.1, KX265012.1, KX265011.1]
>>> stream = Entrez.efetch(db="nucleotide", id=idlist, retmode="xml")
>>> records = Entrez.read(stream)
>>> len(records)
5

這些記錄中的每一個都對應一個 GenBank 記錄。

>>> print(records[0].keys())
['GBSeq_moltype', 'GBSeq_source', 'GBSeq_sequence',
 'GBSeq_primary-accession', 'GBSeq_definition', 'GBSeq_accession-version',
 'GBSeq_topology', 'GBSeq_length', 'GBSeq_feature-table',
 'GBSeq_create-date', 'GBSeq_other-seqids', 'GBSeq_division',
 'GBSeq_taxonomy', 'GBSeq_references', 'GBSeq_update-date',
 'GBSeq_organism', 'GBSeq_locus', 'GBSeq_strandedness']

>>> print(records[0]["GBSeq_primary-accession"])
DQ110336

>>> print(records[0]["GBSeq_other-seqids"])
['gb|DQ110336.1|', 'gi|187237168']

>>> print(records[0]["GBSeq_definition"])
Cypripedium calceolus voucher Davis 03-03 A maturase (matR) gene, partial cds;
mitochondrial

>>> print(records[0]["GBSeq_organism"])
Cypripedium calceolus

您可以使用此方法快速設定搜尋 - 但對於大量使用,請參閱「使用歷史記錄和 WebEnv」章節。

搜尋、下載和解析 GenBank 記錄

GenBank 記錄格式是一種非常流行的方法,用於保存有關序列、序列特徵和其他相關序列資訊。該格式是從 NCBI 資料庫取得資訊的好方法,網址為 https://www.ncbi.nlm.nih.gov/

在本範例中,我們將示範如何查詢 NCBI 資料庫、從查詢中檢索記錄,然後使用 Bio.SeqIO 解析這些記錄 - 這在「從網路解析 GenBank 記錄」章節中有所提及。為了簡單起見,此範例並未利用 WebEnv 歷史記錄功能 - 有關此功能,請參閱「使用歷史記錄和 WebEnv」章節。

首先,我們要進行查詢並找出要檢索的記錄 ID。在這裡,我們將快速搜尋我們最喜歡的生物之一,Opuntia(仙人掌)。我們可以進行快速搜尋,並取得所有對應記錄的 GIs(GenBank 識別碼)。首先,我們檢查有多少記錄。

>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> stream = Entrez.egquery(term="Opuntia AND rpl16")
>>> record = Entrez.read(stream)
>>> for row in record["eGQueryResult"]:
...     if row["DbName"] == "nuccore":
...         print(row["Count"])
...
9

現在,我們下載 GenBank 識別碼列表。

>>> stream = Entrez.esearch(db="nuccore", term="Opuntia AND rpl16")
>>> record = Entrez.read(stream)
>>> gi_list = record["IdList"]
>>> gi_list
['57240072', '57240071', '6273287', '6273291', '6273290', '6273289', '6273286',
'6273285', '6273284']

現在,我們使用這些 GIs 來下載 GenBank 記錄 - 請注意,在舊版本的 Biopython 中,您必須向 Entrez 提供以逗號分隔的 GI 編號列表,從 Biopython 1.59 開始,您可以傳遞一個列表,並且會為您進行轉換。

>>> gi_str = ",".join(gi_list)
>>> stream = Entrez.efetch(db="nuccore", id=gi_str, rettype="gb", retmode="text")

如果您想查看原始的 GenBank 檔案,您可以從此串流讀取並列印出結果。

>>> text = stream.read()
>>> print(text)
LOCUS       AY851612                 892 bp    DNA     linear   PLN 10-APR-2007
DEFINITION  Opuntia subulata rpl16 gene, intron; chloroplast.
ACCESSION   AY851612
VERSION     AY851612.1  GI:57240072
KEYWORDS    .
SOURCE      chloroplast Austrocylindropuntia subulata
  ORGANISM  Austrocylindropuntia subulata
            Eukaryota; Viridiplantae; Streptophyta; Embryophyta; Tracheophyta;
            Spermatophyta; Magnoliophyta; eudicotyledons; core eudicotyledons;
            Caryophyllales; Cactaceae; Opuntioideae; Austrocylindropuntia.
REFERENCE   1  (bases 1 to 892)
  AUTHORS   Butterworth,C.A. and Wallace,R.S.
...

在本例中,我們只是取得原始記錄。若要以更適合 Python 的形式取得記錄,我們可以使用 Bio.SeqIO 將 GenBank 資料解析為 SeqRecord 物件,包括 SeqFeature 物件(請參閱「序列輸入/輸出」章節)。

>>> from Bio import SeqIO
>>> stream = Entrez.efetch(db="nuccore", id=gi_str, rettype="gb", retmode="text")
>>> records = SeqIO.parse(stream, "gb")

現在我們可以逐步瀏覽記錄,並查看我們感興趣的資訊。

>>> for record in records:
...     print(f"{record.name}, length {len(record)}, with {len(record.features)} features")
...
AY851612, length 892, with 3 features
AY851611, length 881, with 3 features
AF191661, length 895, with 3 features
AF191665, length 902, with 3 features
AF191664, length 899, with 3 features
AF191663, length 899, with 3 features
AF191660, length 893, with 3 features
AF191659, length 894, with 3 features
AF191658, length 896, with 3 features

使用這些自動查詢檢索功能比手動操作有很大的優勢。雖然此模組應該遵守 NCBI 每秒最多三個查詢的規則,但 NCBI 還有其他建議,例如避免高峰時段。請參閱「Entrez 指南」章節。特別請注意,為了簡單起見,此範例未使用 WebEnv 歷史記錄功能。對於任何非瑣碎的搜尋和下載工作,您都應該使用此功能,請參閱「使用歷史記錄和 WebEnv」章節。

最後,如果您計劃重複分析,而不是立即從 NCBI 下載檔案並解析它們(如此範例所示),您應該只下載記錄一次並將它們儲存到您的硬碟中,然後解析本地檔案。

尋找生物的譜系

繼續以植物為例,現在讓我們尋找 Cypripedioideae 蘭花科的譜系。首先,我們在 Taxonomy 資料庫中搜尋 Cypripedioideae,這會產生一個 NCBI 分類識別碼。

>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> stream = Entrez.esearch(db="Taxonomy", term="Cypripedioideae")
>>> record = Entrez.read(stream)
>>> record["IdList"]
['158330']
>>> record["IdList"][0]
'158330'

現在,我們使用 efetch 從 Taxonomy 資料庫下載此條目,然後解析它。

>>> stream = Entrez.efetch(db="Taxonomy", id="158330", retmode="xml")
>>> records = Entrez.read(stream)

同樣地,此記錄儲存了大量資訊。

>>> records[0].keys()
['Lineage', 'Division', 'ParentTaxId', 'PubDate', 'LineageEx',
 'CreateDate', 'TaxId', 'Rank', 'GeneticCode', 'ScientificName',
 'MitoGeneticCode', 'UpdateDate']

我們可以從此記錄直接取得譜系。

>>> records[0]["Lineage"]
'cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina;
 Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliopsida;
 Liliopsida; Asparagales; Orchidaceae'

記錄資料包含的不僅僅是這裡顯示的資訊 - 例如,查看 "LineageEx" 而不是 "Lineage",您也會取得譜系條目的 NCBI 分類識別碼。

使用歷史記錄和 WebEnv

通常,您會想進行一系列連結查詢。最典型的情況是,執行搜尋、可能精煉搜尋,然後檢索詳細的搜尋結果。您可以透過對 Entrez 進行一系列獨立呼叫來完成此操作。然而,NCBI 更希望您利用其歷史記錄支援 - 例如,結合 ESearch 和 EFetch。

歷史記錄支援的另一個典型用法是結合 EPost 和 EFetch。您可以使用 EPost 上傳識別碼列表,這會啟動新的歷史記錄會話。然後,您可以使用 EFetch 透過參照會話(而不是識別碼)下載記錄。

使用歷史記錄搜尋和下載序列

假設我們想要搜尋並下載所有 Opuntia rpl16 核苷酸序列,並將它們儲存到 FASTA 檔案中。如「搜尋、下載和解析 GenBank 記錄」章節所示,我們可以天真地結合 Bio.Entrez.esearch() 來取得 Accession 編號列表,然後呼叫 Bio.Entrez.efetch() 來下載它們。

然而,經核准的方法是使用歷史記錄功能執行搜尋。然後,我們可以參照搜尋結果來擷取結果 - NCBI 可以預期並快取這些結果。

若要執行此操作,請像平常一樣呼叫 Bio.Entrez.esearch(),但要額外加上 usehistory="y" 引數。

>>> from Bio import Entrez
>>> Entrez.email = "history.user@example.com"  # Always tell NCBI who you are
>>> stream = Entrez.esearch(
...     db="nucleotide", term="Opuntia[orgn] and rpl16", usehistory="y", idtype="acc"
... )
>>> search_results = Entrez.read(stream)
>>> stream.close()

如先前(請參閱「搜尋、下載和解析 Entrez 核苷酸記錄」章節)所述,XML 輸出包含前 retmax 個搜尋結果,其中 retmax 預設為 20。

>>> acc_list = search_results["IdList"]
>>> count = int(search_results["Count"])
>>> len(acc_list)
20
>>> count
28

您也會獲得兩個額外的資訊,WebEnv 會話 Cookie 和 QueryKey

>>> webenv = search_results["WebEnv"]
>>> query_key = search_results["QueryKey"]

將這些值儲存在變數 session_cookiequery_key 中後,我們可以使用它們作為 Bio.Entrez.efetch() 的參數,而不是將 GI 編號作為識別碼。

雖然對於小型搜尋,您可以一次下載所有內容,但最好分批下載。您可以使用 retstartretmax 參數來指定您要傳回的搜尋結果範圍(使用從零開始的計數,表示開始的條目,以及要傳回的最大結果數)。請注意,如果 Biopython 在與 NCBI 通訊時遇到像 HTTP 500 回應這樣的暫時性錯誤,它會自動嘗試幾次。例如,

# This assumes you have already run a search as shown above,
# and set the variables count, webenv, query_key

batch_size = 3
output = open("orchid_rpl16.fasta", "w")
for start in range(0, count, batch_size):
    end = min(count, start + batch_size)
    print("Going to download record %i to %i" % (start + 1, end))
    stream = Entrez.efetch(
        db="nucleotide",
        rettype="fasta",
        retmode="text",
        retstart=start,
        retmax=batch_size,
        webenv=webenv,
        query_key=query_key,
        idtype="acc",
    )
    data = stream.read()
    stream.close()
    output.write(data)
output.close()

為了說明,此範例以三個為一批下載 FASTA 記錄。除非您正在下載基因體或染色體,否則您通常會選擇更大的批次大小。

使用歷史記錄搜尋和下載摘要

這是另一個歷史記錄範例,搜尋去年發表的關於 Opuntia 的論文,然後以 MedLine 格式將它們下載到檔案中。

from Bio import Entrez

Entrez.email = "history.user@example.com"
search_results = Entrez.read(
    Entrez.esearch(
        db="pubmed", term="Opuntia[ORGN]", reldate=365, datetype="pdat", usehistory="y"
    )
)
count = int(search_results["Count"])
print("Found %i results" % count)

batch_size = 10
output = open("recent_orchid_papers.txt", "w")
for start in range(0, count, batch_size):
    end = min(count, start + batch_size)
    print("Going to download record %i to %i" % (start + 1, end))
    stream = Entrez.efetch(
        db="pubmed",
        rettype="medline",
        retmode="text",
        retstart=start,
        retmax=batch_size,
        webenv=search_results["WebEnv"],
        query_key=search_results["QueryKey"],
    )
    data = stream.read()
    stream.close()
    output.write(data)
output.close()

在撰寫本文時,這會產生 28 個匹配項 - 但由於這是一個依日期而定的搜尋,因此結果當然會有所不同。如上面「解析 Medline 記錄」章節所述,您可以使用 Bio.Medline 來解析儲存的記錄。

搜尋引用文獻

回到「ELink:在 NCBI Entrez 中搜尋相關項目」章節,我們提到 ELink 可用於搜尋特定論文的引用文獻。不幸的是,這僅涵蓋為 PubMed Central 編製索引的期刊(為 PubMed 中的所有期刊執行此操作意味著 NIH 要做更多工作)。讓我們針對 Biopython PDB 解析器論文試試看,PubMed ID 為 14630660。

>>> from Bio import Entrez
>>> Entrez.email = "A.N.Other@example.com"  # Always tell NCBI who you are
>>> pmid = "14630660"
>>> results = Entrez.read(
...     Entrez.elink(dbfrom="pubmed", db="pmc", LinkName="pubmed_pmc_refs", id=pmid)
... )
>>> pmc_ids = [link["Id"] for link in results[0]["LinkSetDb"][0]["Link"]]
>>> pmc_ids
['2744707', '2705363', '2682512', ..., '1190160']

太棒了 - 有 11 篇文章。但是,為什麼沒有找到 Biopython 應用程式註釋(PubMed ID 19304878)?嗯,正如您可能從變數名稱中猜到的那樣,它們實際上不是 PubMed ID,而是 PubMed Central ID。我們的應用程式註釋是該列表中第三篇引用的論文,PMCID 為 2682512。

那麼,如果(像我一樣)您寧願取回 PubMed ID 列表呢?嗯,我們可以再次呼叫 ELink 來轉換它們。這變成一個兩步驟的過程,因此現在您應該預期使用歷史記錄功能來完成它(「使用歷史記錄和 WebEnv」章節)。

但是,首先,採用更直接的方法,對 ELink 進行第二次(獨立的)呼叫。

>>> results2 = Entrez.read(
...     Entrez.elink(dbfrom="pmc", db="pubmed", LinkName="pmc_pubmed", id=",".join(pmc_ids))
... )
>>> pubmed_ids = [link["Id"] for link in results2[0]["LinkSetDb"][0]["Link"]]
>>> pubmed_ids
['19698094', '19450287', '19304878', ..., '15985178']

這次,您會立即發現 Biopython 應用程式註釋是第三個命中結果(PubMed ID 為 19304878)。

現在,讓我們再次使用歷史記錄來執行所有操作...待辦

最後,別忘了在 Entrez 呼叫中包含您自己的電子郵件地址。