2013-07-01 2 views
7

У меня есть список записей PubMed вместе с идентификаторами PubMed. Я хотел бы создать скрипт python или использовать python, который принимает идентификационный номер PubMed в качестве ввода, а затем извлекает реферат с веб-сайта PubMed.Получение данных из PubMed с использованием python

До сих пор я встречался с NCBI Eutilities и библиотекой importurl в Python, но я не знаю, как мне следует писать шаблон.

Любые указатели будут оценены.

Спасибо,

ответ

3

Ничего себе, я работал над аналогичным проектом себе только неделю назад!

Редактировать: Недавно я обновил код, чтобы воспользоваться BeautifulSoup. У меня есть свой собственный virtualenv, но вы можете установить его с помощью pip.

В принципе, моя программа принимает опубликованный идентификатор, DOI или текстовый файл строк опубликованных идентификаторов и/или DOI и захватывает информацию о статье. Это может быть легко переделано для собственных нужд, чтобы получить аннотацию, но вот мой код:

import re 
import sys 
import traceback 
from bs4 import BeautifulSoup 
import requests 

class PubMedObject(object): 
    soup = None 
    url = None 

    # pmid is a PubMed ID 
    # url is the url of the PubMed web page 
    # search_term is the string used in the search box on the PubMed website 
    def __init__(self, pmid=None, url='', search_term=''): 
     if pmid: 
      pmid = pmid.strip() 
      url = "http://www.ncbi.nlm.nih.gov/pubmed/%s" % pmid 
     if search_term: 
      url = "http://www.ncbi.nlm.nih.gov/pubmed/?term=%s" % search_term 
     page = requests.get(url).text 
     self.soup = BeautifulSoup(page, "html.parser") 

     # set the url to be the fixed one with the PubMedID instead of the search_term 
     if search_term: 
      try: 
       url = "http://www.ncbi.nlm.nih.gov/pubmed/%s" % self.soup.find("dl",class_="rprtid").find("dd").text 
      except AttributeError as e: # NoneType has no find method 
       print("Error on search_term=%s" % search_term) 
     self.url = url 

    def get_title(self): 
     return self.soup.find(class_="abstract").find("h1").text 

    #auths is the string that has the list of authors to return 
    def get_authors(self): 
     result = [] 
     author_list = [a.text for a in self.soup.find(class_="auths").findAll("a")] 
     for author in author_list: 
      lname, remainder = author.rsplit(' ', 1) 
      #add periods after each letter in the first name 
      fname = ".".join(remainder) + "." 
      result.append(lname + ', ' + fname) 

     return ', '.join(result) 

    def get_citation(self): 
     return self.soup.find(class_="cit").text 

    def get_external_url(self): 
     url = None 
     doi_string = self.soup.find(text=re.compile("doi:")) 
     if doi_string: 
      doi = doi_string.split("doi:")[-1].strip().split(" ")[0][:-1] 
      if doi: 
       url = "http://dx.doi.org/%s" % doi 
     else: 
      doi_string = self.soup.find(class_="portlet") 
      if doi_string: 
       doi_string = doi_string.find("a")['href'] 
       if doi_string: 
        return doi_string 

     return url or self.url 

    def render(self): 
     template_text = '' 
     with open('template.html','r') as template_file: 
      template_text = template_file.read() 

     try: 
      template_text = template_text.replace("{{ external_url }}", self.get_external_url()) 
      template_text = template_text.replace("{{ citation }}", self.get_citation()) 
      template_text = template_text.replace("{{ title }}", self.get_title()) 
      template_text = template_text.replace("{{ authors }}", self.get_authors()) 
      template_text = template_text.replace("{{ error }}", '') 
     except AttributeError as e: 
      template_text = template_text.replace("{{ external_url }}", '') 
      template_text = template_text.replace("{{ citation }}", '') 
      template_text = template_text.replace("{{ title }}", '') 
      template_text = template_text.replace("{{ authors }}", '') 
      template_text = template_text.replace("{{ error }}", '<!-- Error -->') 

     return template_text.encode('utf8') 

def start_table(f): 
    f.write('\t\t\t\t\t\t\t\t\t<div class="resourcesTable">\n'); 
    f.write('\t\t\t\t\t\t\t\t\t\t<table border="0" cellspacing="0" cellpadding="0">\n'); 

def end_table(f): 
    f.write('\t\t\t\t\t\t\t\t\t\t</table>\n'); 
    f.write('\t\t\t\t\t\t\t\t\t</div>\n'); 

def start_accordion(f): 
    f.write('\t\t\t\t\t\t\t\t\t<div class="accordion">\n'); 

def end_accordion(f): 
    f.write('\t\t\t\t\t\t\t\t\t</div>\n'); 

def main(args): 
    try: 
     # program's main code here 
     print("Parsing pmids.txt...") 
     with open('result.html', 'w') as sum_file: 
      sum_file.write('<!--\n') 
     with open('pmids.txt','r') as pmid_file: 
     with open('result.html','a') as sum_file: 
     for pmid in pmid_file: 
      sum_file.write(pmid) 
     sum_file.write('\n-->\n') 
     with open('pmids.txt','r') as pmid_file: 
      h3 = False 
      h4 = False 
      table_mode = False 
      accordion_mode = False 
      with open('result.html', 'a') as sum_file: 
       for pmid in pmid_file: 
        if pmid[:4] == "####": 
         if h3 and not accordion_mode: 
          start_accordion(sum_file) 
          accordion_mode = True 
         sum_file.write('\t\t\t\t\t\t\t\t\t<h4><a href="#">%s</a></h4>\n' % pmid[4:].strip()) 
         h4 = True 
        elif pmid[:3] == "###": 
         if h4: 
          if table_mode: 
           end_table(sum_file) 
           table_mode = False 
          end_accordion(sum_file) 
          h4 = False 
          accordion_mode = False 
         elif h3: 
          end_table(sum_file) 
          table_mode = False 
         sum_file.write('\t\t\t\t\t\t\t\t<h3><a href="#">%s</a></h3>\n' % pmid[3:].strip()) 
         h3 = True       
        elif pmid.strip(): 
         if (h3 or h4) and not table_mode: 
          start_table(sum_file) 
          table_mode = True 
         if pmid[:4] == "http": 
          if pmid[:18] == "http://dx.doi.org/": 
           sum_file.write(PubMedObject(search_term=pmid[18:]).render()) 
          else: 
           print("url=%s" % pmid) 
           p = PubMedObject(url=pmid).render() 
           sum_file.write(p) 
           print(p) 
         elif pmid.isdigit(): 
          sum_file.write(PubMedObject(pmid).render()) 
         else: 
          sum_file.write(PubMedObject(search_term=pmid).render()) 
       if h3: 
        if h4: 
         end_table(sum_file) 
         end_accordion(sum_file) 
        else: 
         end_table(sum_file) 
      pmid_file.close() 
     print("Done!") 

    except BaseException as e: 
     print traceback.format_exc() 
     print "Error: %s %s" % (sys.exc_info()[0], e.args) 
     return 1 
    except: 
     # error handling code here 
     print "Error: %s" % sys.exc_info()[0] 
     return 1 # exit on error 
    else: 
     raw_input("Press enter to exit.") 
     return 0 # exit errorlessly 

if __name__ == '__main__': 
    sys.exit(main(sys.argv)) 

Теперь он возвращает файл HTML на основе информации, которую он скачал. Вот template.txt:

<tr>{{ error }} 
    <td valign="top" class="resourcesICO"><a href="{{ external_url }}" target="_blank"><img src="/image/ico_sitelink.gif" width="24" height="24" /></a></td> 
    <td><a href="{{ external_url }}">{{ title }}</a><br /> 
    {{ authors }}<br /> 
    <em>{{ citation }}</em></td> 
</tr> 

При его запуске программа запросит DOI или Pubmed ID. Если вы его не предоставите, он будет читать pmids.txt.Feel, чтобы использовать код по своему усмотрению.

+0

Спасибо Bobort, я собираюсь настроить этот код так, что он просто получает абстрактную информацию. Кроме того, я буду интегрировать это с другим скриптом, который отображает опубликованный идентификатор в структурное название и название цитаты. –

+0

Почему я получил голос? Как бесполезно просто проголосовать за ответ и уйти! – Bobort

+0

Привет, Боборт, я думаю, что кто-то еще проголосовал за ответ. Я исправлю это для вас. –

1

PubMed изделие имеет вид: http://www.ncbi.nlm.nih.gov/pubmed/?Id

Если вы знаете идентификатор, то вы можете получить выше, и вы будете иметь доступ к статье. Абстрактный содержится в структуре, как:

<div class="abstr"><h3>Abstract</h3><div class=""><p>α-latrotoxin and snake presynaptic phospholipases A2 neurotoxins target the presynaptic membrane of axon terminals of the neuromuscular junction....</p></div></div> 

Вы бы тогда нужен инструмент для извлечения этого. Я бы предложил использовать: http://www.crummy.com/software/BeautifulSoup/bs4/doc/

Вам по-прежнему нужен инструмент для фактического извлечения html. Для этого я бы использовал phantom.js или модуль популярных запросов.

Ваш рабочий хотел бы что-то вроде:

pubmed_ids [1,2,3] 
abstracts = [] 

for id in pubmed_ids: 
html_for_id = requests.get('http://www.ncbi.nlm.nih.gov/pubmed/{0}'.format(id)) 
soup = BeautifulSoup(html_for_id) 
abstract = soup.find('selector for abstract') 
abstracts.append(abstract) 
19

Используя модуль Biopython, который называется Entrez, вы можете легко получить реферат вместе со всеми другими метаданными. Это напечатает реферата:

from Bio.Entrez import efetch 

def print_abstract(pmid): 
    handle = efetch(db='pubmed', id=pmid, retmode='text', rettype='abstract') 
    print handle.read() 

А вот функция, которая будет получать XML и возвращать только аннотацию:

from Bio.Entrez import efetch, read 

def fetch_abstract(pmid): 
    handle = efetch(db='pubmed', id=pmid, retmode='xml') 
    xml_data = read(handle)[0] 
    try: 
     article = xml_data['MedlineCitation']['Article'] 
     abstract = article['Abstract']['AbstractText'][0] 
     return abstract 
    except IndexError: 
     return None 

P.S. Мне действительно нужно было делать такие вещи в реальной задаче, поэтому я организовал код в класс - see this gist.

+1

Это выглядит очень приятным модулем. Я понятия не имел, что он существует. Однако, одна хорошая вещь о моем кодексе заключается в том, что он получает значения DOI, чтобы полученный URL был как можно более общим. Я предполагаю, что такие функции могут существовать в модуле Entrez, но я не изучил его. – Bobort

+0

Я не уверен, что вы подразумеваете под URL ... biopython делает все запросы за кулисами, поэтому вам не нужно играть с любыми URL-адресами. – Karol

+0

Все в порядке. Мое приложение создает «http://dx.doi.org/», чтобы я мог использовать его на веб-сайте. Вместо того, чтобы идти в материал PubMed, я хочу перейти непосредственно к статье. Самый общий способ, который я знаю прямо сейчас, который является программистом, - использовать схему DOI. – Bobort

0

Кажется модуль «модель» может сделать это легко:

from pattern import web 
 
import requests 
 

 
id = 27523945 
 
url = "http://www.ncbi.nlm.nih.gov/pubmed/{0}".format(id) 
 
page = requests.get(url).text.encode('ascii', 'ignore') 
 
dom = web.Element(page) 
 
print(dom.by_tag("abstracttext")[0].content)

Смежные вопросы