【问题标题】:Python, search for text on the line immediately below a known string?Python,在已知字符串正下方的行上搜索文本?
【发布时间】:2017-04-21 08:06:25
【问题描述】:

我使用 python 模块 BeautifulSoup 编写了一个脚本来从网页获取 xml。此网页包含描述使用基因组数据的项目的信息,我想提取所有 PUBMED ID(来自该项目的出版物的唯一 ID 号)。每个 PUBMED ID 都是一个 8 位数字。

我尝试了两种不同的方法来提取 PUBMED ID,但两者都存在问题。首先,我使用这段代码来提取完整​​的 xml:

url = 'http://www.ebi.ac.uk/ena/data/view/PRJEB2357&display=xml'
project_page = urlopen(url)
soup = BeautifulSoup(project_page, "html.parser")
print soup 

这个命令的输出有点像这样:

<db>PUBMED</db>
<id>25101644</id>
</xref_link>
</project_link>
<project_link>
<xref_link>
<db>PUBMED</db>
<id>24509479</id>

(显然这不是 xml 的全部内容,只是与我相关的部分)。

BeautifulSoup 模块包含许多命令,这些命令在此汤中搜索感兴趣的文本,但据我所知,它们都将标签或正在搜索的文本作为输入。我不能在这里使用其中任何一个,因为此页面上除 PUBMED ID 之外的多个文本段具有相同的 xml 标签 (&lt;id&gt;),而且我显然无法使用文本搜索 PUBMED ID如果我不知道它是什么!

我尝试的第二种方法是使用以下代码仅打印 xml 中的文本:

url = 'http://www.ebi.ac.uk/ena/data/view/PRJEB2357&display=xml'
project_page = urlopen(url)
soup = BeautifulSoup(project_page, "html.parser") 
text = soup.text
print text

这次的输出是这样的:

PUBMED
25101644




PUBMED
24509479

此时我有几个想法。首先,python re 模块(python 早期版本中的正则表达式)可用于搜索表达式,但我知道的所有 re 命令都需要至少一部分被搜索的模式作为输入,所以我不认为仅此一项是一种选择。其次,我尝试做这样的事情:

url = 'http://www.ebi.ac.uk/ena/data/view/PRJEB2357&display=xml'
project_page = urlopen(url)
soup2 = BeautifulSoup(project_page, "html.parser") 
text = soup2.text
text = text.replace('\n', ' ').replace(' ', '') #removes all spaces and linebreaks
PMID = re.findall('PUBMED........', text, flags = 0)
print PMID

这给出了这个输出:

[u'PUBMED25101644', u'PUBMED24509479']

所以理论上这可以转换为一个字符串,我只是剪掉了相关的 8 位数字,但这变得非常 hacky,我想在网页上多次运行这个脚本,用于数千个项目和数量每个项目的 PUBMED ID 会有所不同,因此这种方法不太适合自动化。

我想要的是一种搜索单词“PUBMED”的每个实例的方法,无论是在生汤中还是在文本中,并仅提取下一行的 PUBMED ID。有人对如何做到这一点有任何建议吗?

【问题讨论】:

    标签: python regex xml web-scraping beautifulsoup


    【解决方案1】:

    查找所有出现的PUBMED 并获取next siblings

    [pubmed.find_next_sibling("ID").get_text() 
     for pubmed in soup.find_all("DB", text="PUBMED")]
    

    或者,创建一个search function

    search = lambda tag: tag.name == "ID" and tag.find_previous_sibling("DB", text="PUBMED")
    print([pubmed.get_text() for pubmed in soup.find_all(search)])
    

    请注意,您应该使用xml 解析器而不是html.parser

    soup = BeautifulSoup(project_page, "xml")
    

    演示:

    In [1]: from urllib2 import urlopen
    
    In [2]: from bs4 import BeautifulSoup
    
    In [3]: url = 'http://www.ebi.ac.uk/ena/data/view/PRJEB2357&display=xml'
    
    In [4]: project_page = urlopen(url)
    
    In [5]: soup = BeautifulSoup(project_page, "xml")
    
    In [6]: [pubmed.find_next_sibling("ID").get_text() 
       ...:  for pubmed in soup.find_all("DB", text="PUBMED")]
    Out[6]: [u'25101644', u'24509479']
    
    In [7]: search = lambda tag: tag.name == "ID" and tag.find_previous_sibling("DB", text="PUBMED")
    
    In [8]: [pubmed.get_text() for pubmed in soup.find_all(search)]
    Out[8]: [u'25101644', u'24509479']
    

    【讨论】:

      【解决方案2】:

      您可以直接在正则表达式中使用look behind。 如果文本是

      print text
      PUBMED
      25101644
      
      
      
      
      PUBMED
      24509479
      

      通过使用

      >>> re.findall('(?<=PUBMED\n).+',text)
      ['25101644', '24509479']
      

      如果您只想获取已知字符串后面的数字,请将 .+ 替换为 [\d]+,它只会选择数字。

      希望这会有所帮助。

      【讨论】:

      • 谢谢,除了最后一点,我的输出效果很好,我的输出看起来像这样: [u'25101644', u'24509479'] 即使我包含 [\d]+ 选项.. .
      • 那是因为文本是一个unicode字符串。您可以再尝试这样一行来获取整数列表
      • results = [int(item) for item in re.findall('(?
      【解决方案3】:

      你可以找到db,然后得到它的第一个兄弟

      data = '''<db>PUBMED</db>
      <id>25101644</id>
      </xref_link>
      </project_link>
      <project_link>
      <xref_link>
      <db>PUBMED</db>
      <id>24509479</id>'''
      
      from bs4 import BeautifulSoup
      soup = BeautifulSoup(data, "html.parser")
      #print(soup)
      
      for x in soup.find_all('db'):
          print(x.text, x.fetchNextSiblings()[0].text)
      

      结果

      PUBMED 25101644
      PUBMED 24509479
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-12
        • 1970-01-01
        • 1970-01-01
        • 2011-01-30
        • 1970-01-01
        相关资源
        最近更新 更多