Python BeautifulSoup提取元素之间的文本

ɥɔǝ*_*loɥ 33 python beautifulsoup

我尝试从以下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>
Run Code Online (Sandbox Code Playgroud)

我这样试过:

soup = BeautifulSoup(html)

for hit in soup.findAll(attrs={'class' : 'MYCLASS'}):
    print hit.text
Run Code Online (Sandbox Code Playgroud)

但我得到所有嵌套标签和评论之间的所有文本.

任何人都可以帮助我从中获得"这是我的文字"吗?

kir*_*off 35

详细了解如何浏览解析树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>
Run Code Online (Sandbox Code Playgroud)

要向下移动你解析树contentsstring.

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

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

对于上述情况,也就是说你可以得到

soup.b.string
# u'one'
soup.b.contents[0]
# u'one'
Run Code Online (Sandbox Code Playgroud)

例如,对于多个子节点,您可以使用

pTag = soup.p
pTag.contents
# [u'This is paragraph ', <b>one</b>, u'.']
Run Code Online (Sandbox Code Playgroud)

所以你可以在这里玩,contents并获得你想要的索引的内容.

您还可以迭代标记,这是一个快捷方式.例如,

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>
Run Code Online (Sandbox Code Playgroud)

  • `hit.string` 是 `None`,`hit.contents[0]` 是 `u'\n'`,所以请为问题中的示例提供答案。 (3认同)

Ter*_*ryA 14

你可以使用.contents:

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

  • 谢谢,但文字并不总是在同一个地方.无论如何它会起作用吗? (3认同)

Mar*_*ers 13

.children改为使用:

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

是的,这有点像舞蹈.

输出:

>>> 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
Run Code Online (Sandbox Code Playgroud)

  • 这是唯一不依赖于文本与特定其他文本的顺序或位置关系的解决方案,而是从指定标签/元素中提取所有文本,同时忽略子标签/元素的文本(或其他内容)。谢谢!这很尴尬,但它有效并解决了我的问题(我不是 OP,但有类似的需求)。 (3认同)

Gre*_*ler 10

用你自己的汤对象:

soup.p.next_sibling.strip()
Run Code Online (Sandbox Code Playgroud)
  1. 你直接用soup.p*抓住<p> (这取决于它是解析树中的第一个<p>)
  2. 然后使用返回next_sibling的标记对象,soup.p因为所需的文本嵌套在与<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
Run Code Online (Sandbox Code Playgroud)


Ben*_*own 6

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

真实答案:您需要一个不变的参考点,您可以从中获得目标.

你在评论中提到了海德罗的答案,你想要的文字并不总是在同一个地方.找到一种相对于某个元素位于同一位置的感觉.然后弄清楚如何使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中返回您的目标.