次の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」を取得するのを助けることができますか?
ナビゲート方法の詳細については、 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>
解析ツリーを下に移動するには、contents
とstring
があります。
コンテンツは、ページ要素内に含まれる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>
.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()
soup.p
*で<p>を直接取得します(これは、解析ツリーの最初の<p>に依存します)next_sibling
が返すタグオブジェクトでsoup.p
を使用します。これは、目的のテキストが<p>と同じ解析ツリーのレベルでネストされるためです.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
短い答え: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でターゲットを返します。
soup = BeautifulSoup(html)
for hit in soup.findAll(attrs={'class' : 'MYCLASS'}):
hit = hit.text.strip()
print hit
これは印刷されます:このISマイテキストこれを試してください。
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>