LifeScience Hack

生物系創薬研究者がAI(誇大表示)を手に入れるまでの過程(Python、Deep Learning、ライフサイエンス)

Uniprotからxmlを取ってきたときにうまくパースできずに困った話

お久しぶりになりました。
相変わらず、ちょこまかといろいろやっております。

最近、UniProtからデータを引っこ抜くことが多いのですが、
UniProtからxmlでデータを取得した後、pythonのlxmlで目的の項目を抜き出す際に
ちょっとしたトラップがありました。
その際に詰まったことがありましたので、メモ代わりに記事にします。

UniProtとは

UniProtとは The Universal Protein Resourceのことで、
タンパク質の配列とその機能についての情報が網羅的に収載されている、
巨大なデータベースです。

https://www.uniprot.org

UniProt APIを用いてデータ取得

Pubmedと同様にUniProtにもAPIがあり、
クエリを投げることによって自動的に情報を取得できます。
今回はHPのexampleにもある以下のクエリを例に取りたいと思います。
https://www.uniprot.org/uniprot/P12345.xml

詳細は上のクエリを開いていただければ分かりますが、
FABP-1というタンパク質の情報のxmlデータとなります。

f:id:tottoham:20191109210942p:plain
uniprotのxmlデータ

xmlを用いてparseできない????

xmlならpythonなどを用いて、ササッと目的の項目を取得となります。
試しに以下のコードを書いて、タンパク質のrecommendedNameを取得しようとすると、 なぜか空白のデータが帰ってきます。

#うまく行かない例です
import requests
from lxml import etree

query = 'https://www.uniprot.org/uniprot/P12345.xml'
response = requests.get(query)
root = etree.fromstring(response.content)
fullname = root.findall('.//recommendedName/fullName')
fullname
#[]空のデータが返ってきます。

f:id:tottoham:20191109215719p:plain

uniprotのxml parseには名前空間の指定が必要

xmlのパースに余りなれていないため、
書き方が悪いのか??と思ってかなり頑張ったのですが、
いくらやっても空のリストしか返ってきませんでした。

色々と調べた結果、xmlには名前空間(namespace)が指定されている場合、
それをちゃんと指定してあげなければいけないようです。
xml名前空間が指定されているかどうかは、以下の部分を見ればわかります。
f:id:tottoham:20191110131027p:plain xmlns = のところに名前空間が書かれていますね。

また、lxmlのnsmapでも確認できます。

print(root.nsmap)
#{None: 'http://uniprot.org/uniprot',
#'xsi': 'http://www.w3.org/2001/XMLSchema-instance'}

名前空間を指定してxmlをparseする

さて、それでは名前空間を指定してparseしてみます。
xpathで行く場合は、
root.xpath('ここにxpathを指定', namespces = root.nsmap)

lxmlのfindを使う場合は、
root.find('ここにxpathを指定', root.nsmap)

です。
が、今回の様にnamespaceにNoneが入っている場合は、 lxmlのxpathはうまく行きませんので、
findの方を使いましょう。

import requests
from lxml import etree

query = 'https://www.uniprot.org/uniprot/P12345.xml'
response = requests.get(query)
root = etree.fromstring(response.content)
fullname = root.find('.//recommendedName/fullName',root.nsmap)
print(fullname.text)
#'Aspartate aminotransferase, mitochondrial'

上手くparseできましたね。

今回は以上になります。