BeautifulSoup4で親子、兄弟、前後要素の検索方法
みなさまおはこんばんにちは、せなです
今回はBeautifulSoup4で親要素や子要素への移動と検索の方法について説明したいと思います
始めに
BeautifulSoup4の基本について知りたい方は以下の記事も参考にしてみてください
リンク:BeautifulSoup4の基本的な使い方
リンク:BeautifulSoup4のタグオブジェクトの基本的な使い方
HTML構成
以下のコードを使用することを前提に説明しています
from bs4 import BeautifulSoup
html = """<html><head><title>せなブログ</title></head>
<p id="site"><a href="https://senablog.com/">せなブログ</a></p>
<p class="desc">疑問に思ったことをサクッと解説!一日一記事22時更新です</p>
<a href="https://senablog.com/category/programming/" class="category" id="tag1">プログラミング</a>
<a href="https://senablog.com/category/programming/python/" class="category" id="tag2">Python</a>
<a href="https://senablog.com/category/zakki/" class="category" id="tag3">雑記</a>
<p class="item"></p>"""
soup = BeautifulSoup(html, 'html.parser')
タグ名での検索
Beautiful Soupでの最も簡単な検索方法はタグ名を使うことです
例えばtitleタグを取得したい場合は、soup.title
で取得できます
print(soup.title)
----結果----
<title>せなブログ</title>
また、タグの子要素を取り出したいなら、soup.a.string
とすれば以下のように取得することもできます
s = soup.a.string
print(s)
----結果----
せなブログ
ただし、以上の方法では一番最初のタグしか取得できません
複数の同じタグを取得したい場合は、find_all()
などのメソッドを使用する必要があります
[print(tag) for tag in soup.find_all('a')]
----結果----
<a href="https://senablog.com/">せなブログ</a>
<a class="category" href="https://senablog.com/category/programming/" id="tag1">プログラミング</a>
<a class="category" href="https://senablog.com/category/programming/python/" id="tag2">Python</a>
<a class="category" href="https://senablog.com/category/zakki/" id="tag3">雑記</a>
親要素の検索
parent
親要素へアクセスするには.parent
を使用します
title_tag = soup.title
print(title_tag)
print(title_tag.parent)
----結果----
<title>せなブログ</title>
<head><title>せなブログ</title></head>
titleタグのテキストはtitleタグの子要素に当たり、テキストの親要素になります
title_tag = soup.title
print(title_tag.string)
title = title_tag.string
print(title.parent)
----結果----
せなブログ
<title>せなブログ</title>
parents
そのタグの全ての祖先を取得するには、.parents
を使用します
dep = soup.a
print(dep)
# aタグから上の親要素を取得
[print(parent.name) for parent in dep.parents]
----結果----
<a href="https://senablog.com/">せなブログ</a>
p
html
[document]
子要素の検索
contents
子要素は.contents
を使用することでリストとして取得できます
head = soup.head
print(head)
print(head.contents)
title = head.contents[0]
print(title)
print(title.contents[0])
----結果----
<head><title>せなブログ</title></head>
[<title>せなブログ</title>]
<title>せなブログ</title>
せなブログ
また、.children
を使用することでタグの子要素を取得することができます
[print(text) for text in title.children]
----結果----
せなブログ
descendants
.descendants
は子孫要素全てをジェネレーターオブジェクトとして取得します
head = soup.head
print(type(head.descendants))
----結果----
<class 'generator'>
.descendants
の子孫要素を全て取得するには以下のようfor
などを使用します
head = soup.head
[print(tag) for tag in head.descendants]
----結果----
<title>せなブログ</title>
せなブログ
.children
は.descendants
とよく似ているように思うかもしれません
ですが、以下を見れば分かる通り取得する要素数は明確に違います
print(len(list(soup.children)))
print(len(list(soup.descendants)))
----結果----
1
22
.childrenは子要素を取得します(今回の場合は「html」のみ)
.descendantsは子孫要素まで取得します(「html」~「最後のpタグまで全て」)
string
.string
は子要素がNavigableStringオブジェクトであれば使用できます
「title.contents[0]
」でも同様の結果を期待することができます
title = soup.title
print(title.string)
----結果----
せなブログ
また、.string
はタグが複数の子要素を持っている場合はNoneが結果として返却されます
strings
.strings
はタグの子孫要素からNavigableStringオブジェクトを全て取得することができます
[print(tag, end='') for tag in soup.strings]
----結果----
せなブログ
せなブログ
疑問に思ったことをサクッと解説!一日一記事22時更新です
プログラミング
Python
雑記
.strings
の場合は余計な空白などが表示されてしまいます
それらを取り除きたい場合には.stripped_strings
を使用します
[print(tag) for tag in soup.stripped_strings]
----結果----
せなブログ
せなブログ
疑問に思ったことをサクッと解説!一日一記事22時更新です
プログラミング
Python
雑記
兄弟要素の検索
兄弟要素はインデントを揃えたときに同じ階層に属しているタグのことを言います
next_siblingとprevious_sibling
.next_sibling
と.previous_sibling
は同じ階層に属するタグを辿るときに使用します
まずは、以下をみてください
print(soup.p.next_sibling)
print(soup.p.previous_sibling)
----結果----
\n
\n
これは最初のpタグを指定していますので、普通は次(前)のタグが表示されるはずです
ですが、パースしたHTMLの前後には改行が含まれているため正しい結果を得られません
その場合にどうするかというとsiblingを再度使用します
print(soup.p.next_sibling.next_sibling)
print(soup.p.previous_sibling.previous_sibling)
----結果----
<p class="desc">疑問に思ったことをサクッと解説!一日一記事22時更新です</p>
<head><title>せなブログ</title></head>
next_siblingsとprevious_siblings
.next_siblings
と.previous_siblings
はイテレーターとして使うことができ、複数の兄弟要素を全て取得したいときに使用します
[print(tag, end='') for tag in soup.p.next_siblings]
----結果----
<p class="desc">疑問に思ったことをサクッと解説!一日一記事22時更新です</p>
<a class="category" href="https://senablog.com/category/programming/" id="tag1">プログラミング</a>
<a class="category" href="https://senablog.com/category/programming/python/" id="tag2">Python</a>
<a class="category" href="https://senablog.com/category/zakki/" id="tag3">雑記</a>
<p class="item"></p>
[print(tag, end='') for tag in soup.find(id='tag3').previous_siblings]
----結果----
<a class="category" href="https://senablog.com/category/programming/python/" id="tag2">Python</a>
<a class="category" href="https://senablog.com/category/programming/" id="tag1">プログラミング</a>
<p class="desc">疑問に思ったことをサクッと解説!一日一記事22時更新です</p>
<p id="site"><a href="https://senablog.com/">せなブログ</a></p>
<head><title>せなブログ</title></head>
前後要素の検索
next_elementとprevious_element
.next_element
と.previous_element
はタグの前後の要素を取得するときに使用します
「siblingと同じでは?」と思われるかもしれませんがelementとsiblingは全く違います
以下を見てください
print(soup.p.previous_sibling.previous_sibling)
print(soup.p.previous_element.previous_element)
print(soup.p.previous_element.previous_element.previous_element)
print(soup.p.previous_element.previous_element.previous_element.previous_element)
----結果----
<head><title>せなブログ</title></head>
せなブログ
<title>せなブログ</title>
<head><title>せなブログ</title></head>
上はsiblingを下3行はelementを使用しています
結果を見てみると内容が違います
なぜなら.previous_elment
はタグの一つ後のタグを取得するからです
これは.next_element
と.next_sibiling
でも同じことが言えます
next_elementsとprevious_elements
.next_elementsと.previous_elementsはイテレーターとして使用することができ、前後の要素を全て取得することができます
[print(tag, end='') for tag in soup.p.next_elements]
----結果----
<a href="https://senablog.com/">せなブログ</a>せなブログ
<p class="desc">疑問に思ったことをサクッと解説!一日一記事22時更新です</p>疑問に思ったことをサクッと解説!一日一記事22時更新です
<a class="category" href="https://senablog.com/category/programming/" id="tag1">プログラミング</a>プログラミング
<a class="category" href="https://senablog.com/category/programming/python/" id="tag2">Python</a>Python
<a class="category" href="https://senablog.com/category/zakki/" id="tag3">雑記</a>雑記
<p class="item"></p>
[print(tag, end='') for tag in soup.find(id='tag3').previous_elements]
----結果----
Python<a class="category" href="https://senablog.com/category/programming/python/" id="tag2">Python</a>
プログラミング<a class="category" href="https://senablog.com/category/programming/" id="tag1">プログラミング</a>
疑問に思ったことをサクッと解説!一日一記事22時更新です<p class="desc">疑問に思ったことをサクッと解説!一日一記事22時更新です</p>
せなブログ<a href="https://senablog.com/">せなブログ</a><p id="site"><a href="https://senablog.com/">せなブログ</a></p>
せなブログ<title>せなブログ</title><head><title>せなブログ</title></head><html><head><title>せなブログ</title></head>
<p id="site"><a href="https://senablog.com/">せなブログ</a></p>
<p class="desc">疑問に思ったことをサクッと解説!一日一記事22時更新です</p>
<a class="category" href="https://senablog.com/category/programming/" id="tag1">プログラミング</a>
<a class="category" href="https://senablog.com/category/programming/python/" id="tag2">Python</a>
<a class="category" href="https://senablog.com/category/zakki/" id="tag3">雑記</a>
<p class="item"></p></html>
ディスカッション
コメント一覧
まだ、コメントがありません