繁体   English   中英

Python BeautifulSoup提取元素之间的文本

[英]Python BeautifulSoup extract text between element

我尝试从以下HTML中提取“这就是我的文字”:

<html>
<body>
<table>
   <td class="MYCLASS">
      <!-- a comment -->
      <a hef="xy">Text</a>
      <p>something</p>
      THIS IS MY TEXT
      <p>something else</p>
      </br>
   </td>
</table>
</body>
</html>

我这样尝试过:

soup = BeautifulSoup(html)

for hit in soup.findAll(attrs={'class' : 'MYCLASS'}):
    print hit.text

但是我得到了所有嵌套标签和注释之间的所有文本。

谁能帮我从中获得“这就是我的文字”吗?

BeautifulSoup了解有关如何在解析树中导航的更多信息。 解析树有tagsNavigableStrings (因为这是文本)。 一个例子

from BeautifulSoup import BeautifulSoup 
doc = ['<html><head><title>Page title</title></head>',
       '<body><p id="firstpara" align="center">This is paragraph <b>one</b>.',
       '<p id="secondpara" align="blah">This is paragraph <b>two</b>.',
       '</html>']
soup = BeautifulSoup(''.join(doc))

print soup.prettify()
# <html>
#  <head>
#   <title>
#    Page title
#   </title>
#  </head>
#  <body>
#   <p id="firstpara" align="center">
#    This is paragraph
#    <b>
#     one
#    </b>
#    .
#   </p>
#   <p id="secondpara" align="blah">
#    This is paragraph
#    <b>
#     two
#    </b>
#    .
#   </p>
#  </body>
# </html>

要向下移动分析树,您需要contentsstring

  • content是页面元素中包含的Tag和NavigableString对象的有序列表

  • 如果标签只有一个子节点,并且该子节点是字符串,则该子节点可以作为tag.string以及tag.contents [0]使用

对于上面的,这就是说你可以得到

soup.b.string
# u'one'
soup.b.contents[0]
# u'one'

对于几个子节点,例如

pTag = soup.p
pTag.contents
# [u'This is paragraph ', <b>one</b>, u'.']

因此,在这里您可以播放contents并在所需的索引处获取内容。

您还可以遍历Tag,这是一种快捷方式。 例如,

for i in soup.body:
    print i
# <p id="firstpara" align="center">This is paragraph <b>one</b>.</p>
# <p id="secondpara" align="blah">This is paragraph <b>two</b>.</p>

您可以使用.contents

>>> for hit in soup.findAll(attrs={'class' : 'MYCLASS'}):
...     print hit.contents[6].strip()
... 
THIS IS MY TEXT

使用.children代替:

from bs4 import NavigableString, Comment
print ''.join(unicode(child) for child in hit.children 
    if isinstance(child, NavigableString) and not isinstance(child, Comment))

是的,这有点跳舞。

输出:

>>> for hit in soup.findAll(attrs={'class' : 'MYCLASS'}):
...     print ''.join(unicode(child) for child in hit.children 
...         if isinstance(child, NavigableString) and not isinstance(child, Comment))
... 




      THIS IS MY TEXT

用自己的汤对象:

soup.p.next_sibling.strip()
  1. 您直接用soup.p *抓住<p>(这取决于它是解析树中的第一个<p>)
  2. 然后在soup.p返回的标签对象上使用next_sibling ,因为所需的文本嵌套在与<p>相同的解析树级别上
  3. .strip()只是删除前导和尾随空格的Python str方法

*否则,只需使用您选择的过滤器 找到元素

在解释器中,这看起来像:

In [4]: soup.p
Out[4]: <p>something</p>

In [5]: type(soup.p)
Out[5]: bs4.element.Tag

In [6]: soup.p.next_sibling
Out[6]: u'\n      THIS IS MY TEXT\n      '

In [7]: type(soup.p.next_sibling)
Out[7]: bs4.element.NavigableString

In [8]: soup.p.next_sibling.strip()
Out[8]: u'THIS IS MY TEXT'

In [9]: type(soup.p.next_sibling.strip())
Out[9]: unicode

简短答案: soup.findAll('p')[0].next

真正的答案:您需要一个不变的参考点,您可以从该参考点到达目标。

您在对Haidro的回答的评论中提到,所需的文本并非始终位于同一位置。 找到相对于某个元素它在同一位置的感觉。 然后找出如何使BeautifulSoup沿不变路径浏览解析树。

例如,在您在原始帖子中提供的HTML中,目标字符串会立即出现在第一个段落元素之后,并且该段落不为空。 由于findAll('p')将查找段落元素,因此soup.find('p')[0]将成为第一个段落元素。

在这种情况下,您可以使用soup.find('p')soup.findAll('p')[n]更通用,因为您的实际情况可能需要第5段或类似内容。

next字段属性将是树中的下一个已解析元素,包括子元素。 因此, soup.findAll('p')[0].next包含该段落的文本, soup.findAll('p')[0].next.next将在提供的HTML中返回目标。

soup = BeautifulSoup(html)
for hit in soup.findAll(attrs={'class' : 'MYCLASS'}):
  hit = hit.text.strip()
  print hit

它将打印:这是我的文字尝试这个。

BeautifulSoup文档提供了有关使用extract方法从文档中删除对象的示例。 在以下示例中,目的是从文档中删除所有注释:

移除元素

一旦有了对元素的引用,就可以使用extract方法将其从树中撕下。 此代码从文档中删除所有注释

from BeautifulSoup import BeautifulSoup, Comment
soup = BeautifulSoup("""1<!--The loneliest number-->
                    <a>2<!--Can be as bad as one--><b>3""")
comments = soup.findAll(text=lambda text:isinstance(text, Comment))
[comment.extract() for comment in comments]
print soup
# 1
# <a>2<b>3</b></a>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM