web-dev-qa-db-ja.com

Python BeautifulSoupは要素間のテキストを抽出します

次のHTMLから「THIS IS MY TEXT」を抽出しようとしています。

<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

しかし、ネストされたすべてのタグとコメントの間にあるすべてのテキストを取得します。

誰も私がこれから「THIS IS MY TEXT」を取得するのを助けることができますか?

33

ナビゲート方法の詳細については、 BeautifulSoupの解析ツリーを使用 を参照してください。解析ツリーにはtagsおよびNavigableStringsがあります(これはIS A TEXTとして)。例

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があります。

  • コンテンツは、ページ要素内に含まれるTagおよびNavigableStringオブジェクトの順序付きリストです

  • タグに子ノードが1つしかなく、その子ノードが文字列である場合、子ノードは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で遊んで、あなたが望むインデックスでコンテンツを取得できる。

タグを繰り返し処理することもできます。これはショートカットです。例えば、

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>
35
kiriloff

.contents を使用できます。

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

代わりに .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
12
Martijn Pieters

独自のスープオブジェクトで:

soup.p.next_sibling.strip()
  1. soup.p *で<p>を直接取得します(これは、解析ツリーの最初の<p>に依存します)
  2. next_siblingが返すタグオブジェクトでsoup.pを使用します。これは、目的のテキストが<p>と同じ解析ツリーのレベルでネストされるためです
  3. .strip()は、先頭および末尾の空白を削除するPython strメソッドです

*それ以外の場合 findfilter (s)の選択を使用した要素

インタープリターでは、これは次のようになります。

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
10
Gregory Kremler

短い答え:soup.findAll('p')[0].next

本当の答え:ターゲットに到達できる不変の参照ポイントが必要です。

Haidroの答えに対するコメントの中で、あなたが望むテキストは常に同じ場所にあるとは限らないと述べています。ある要素に対して同じ場所にあるという感覚を見つけてください。次に、BeautifulSoupがその不変のパスに従って解析ツリーをナビゲートする方法を見つけます。

たとえば、元の投稿で提供するHTMLでは、ターゲット文字列は最初の段落要素の直後に表示され、その段落は空ではありません。 findAll('p')は段落要素を見つけるため、soup.find('p')[0]が最初の段落要素になります。

この場合、soup.find('p')を使用できますが、実際のシナリオでは5番目の段落などが必要になるため、soup.findAll('p')[n]はより一般的です。

nextフィールド属性は、子を含むツリー内の次に解析される要素になります。したがって、soup.findAll('p')[0].nextは段落のテキストを含み、soup.findAll('p')[0].next.nextは提供されたHTMLでターゲットを返します。

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

これは印刷されます:このISマイテキストこれを試してください。

2
Naiswita

BeautifulSoup documentation は、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>
1
alireza sanaee