ユーニックス総合研究所

  • home
  • archives
  • beautifulsoup4-find

【Python】BeautifulSoup4のfind()の使い方をわかりやすく解説

  • 作成日: 2021-08-09
  • 更新日: 2023-12-26
  • カテゴリ: Python

BeautifulSoup4のfindの使い方

Pythonの外部ライブラリであるBeautifulSoup4を使うとHTML/XMLを簡単にパースすることが出来ます。
この記事ではBeautifulSoup4の中でも利用頻度の高いfind()メソッドについて解説します。

find()メソッドと同じインターフェースを持つメソッドは複数あり、find()の使い方を覚えればこれらのメソッドも使うことが出来るようになります。
具体的には↓を見ていきます。

  • 前提とするHTML
  • find()を使う準備
  • find()の構造
  • find()は見つからなかったらNoneを返す
  • nameにタグ名を指定してタグを取得
  • attrsに属性名と属性値を指定して要素を取得する
  • **kwargsにidとclass_を指定して要素を取得する
  • textに文字列を指定して要素を取得する
  • recursiveで検索深度を調整する

関連記事
BeautifulSoup4のattrsの使い方【Python】
BeautifulSoup4でtableをパースする方法【Python, スクレイピング】
BeautifulSoup4でhrefの値を捕まえる方法

前提とするHTML

今回の解説では↓のHTMLコードを前提に解説します。
このHTMLをBeautifulSoup4でパースして、タグなどを取得します。

html = '''  
<div>  
    <p>one</p>  
    <span class="bird">two</span>  
    <strong id="pig" class="dog">three</strong>  
    <p key1="value1">four</p>  
    <p key1="value1" key2="value2">five</p>  
    <div>  
        <p class="cow">six</p>  
    </div>  
</div>  
'''  

HTMLは<p>タグや<span><strong>などのタグが複数含まれるHTMLで、階層もあります。
find()は階層を辿っていくメソッドなので、このようにサンプルのHTMLで階層を付けるようにしています。
また、各タグにはidclassなどの属性も付けています。これらはfind()の引数で指定されます。

find()を使う準備

find()を使うにはBeautifulSoupをインポートしておく必要があります。

from bs4 import BeautifulSoup  

そして先述のHTMLをコンストラクタに渡してスープにします。

soup = BeautifulSoup(html, 'html.parser')  
print(type(soup))  
# <class 'bs4.BeautifulSoup'>  

今回はパーサーはhtml.parserを指定しています。
これは標準ライブラリで用意されている標準的なPythonのHTMLパーサーです。
速度も厳密性もほどほどな中立的なパーサーです。

find()メソッドはこのsoupのメソッドです。
以降はこのsoup変数からfind()を使います。

find()の構造

find()メソッドの構造は↓のようになっています。

def find(  
    self,  
    name=None,  # 検索するタグ名  
    attrs={},  # 検索する属性と属性値  
    recursive=True,  # 再帰的に検索するならTrue  
    text=None,  # 検索するタグのテキスト  
    **kwargs  # キーワード引数  
):  
    ...  

find()は↑のような引数を取り、返り値を1つ返します。
タグが見つかった場合はタグ(bs4.element.Tag)を返し、タグが見つからなかった場合はNoneを返します。

nameはタグ名です。これに検索したいタグ名を指定します。たとえばpとかdivです。
attrsは検索するタグの属性名と属性値の辞書です。これはたとえば{ 'class': 'bird' }などのようになります。
recursiveは検索を再帰的に行うかどうかのフラグです。このフラグはデフォルトでTrueです。フラグがFalseのとき、検索は1階層にのみ行われ、再帰的に階層を辿らなくなります。
textは検索するタグのテキスト・コンテンツです。textを指定した場合、返り値はタグではなくNavigableStringになります。

find()の実装は非常にシンプルです。内部ではfind_all()を呼び出して、その結果の第1要素を返すだけのメソッドです。
つまりfind()の実装のほとんどはfind_all()です。

find()は見つからなかったらNoneを返す

find()はタグが見つからなかった場合はNoneを返します。
↓の場合、第1引数にタグ名nothingを指定していますが、そのようなタグ名のタグは存在しないため、Noneが返ってきています。

tag = soup.find('nothing')  
print(tag)  
# None  

nameにタグ名を指定してタグを取得

find()の第1引数のnameにタグ名を指定すると、find()はそのタグ名のタグを検索します。

tag = soup.find('p')  
print(type(tag))  # <class 'bs4.element.Tag'>  
print(tag.text)  # one  

明示的にnameを指定しても問題ありません。

tag = soup.find(name='p')  
print(tag.text)  
# one  

タグ名にはタグの名前(div, p, spanなど)をどれでも指定可能です。

tag = soup.find('span')  
print(tag.text)  
# two  

attrsに属性名と属性値を指定して要素を取得する

find()の引数のattrsに辞書で属性と属性値を指定すると、その属性と属性値を持つタグを検索できます。

tag = soup.find(attrs={ 'class': 'bird' })  
print(type(tag))  # <class 'bs4.element.Tag'>  
print(tag.text)  # two  

attrsの値を複数指定した場合、検索はAND検索になります。
つまり↓の場合、key1key2の両方を持っているタグを取得することになります。

tag = soup.find(attrs={ 'key1': 'value1', 'key2': 'value2' })  
print(tag.text)  
# five  

attrsにはclassidも指定可能ですが、これらは利用頻度の高い属性のため、後述のキーワード引数で指定することが出来ます。

**kwargsにidとclass_を指定して要素を取得する

find()のキーワード引数にidを指定すると、その値のid属性を持つタグを検索できます。

tag = soup.find(id='pig')  
print(tag.text)  
# three  

↑の場合はidpigのタグを検索しています。

tag = soup.find(class_='dog')  
print(tag.text)  
# three  

textに文字列を指定して要素を取得する

find()の引数textに文字列を指定すると、その文字列を持つタグを検索できます。

ns = soup.find(text='two')  
print(type(ns))  # <class 'bs4.element.NavigableString'>  
print(ns)  # two  

textを指定した場合は返り値はNavigableStringになります。
見つからなかった場合はNoneを返すので、目的のテキストを持っているタグがあるかどうかの判定に使えそうです。

def has_text(soup, text):  
    return bool(soup.find(text=text))  

print(has_text(soup, 'one'))  # True  
print(has_text(soup, 'nothing'))  # False  

recursiveで検索深度を調整する

find()の引数recursiveTrueを指定すると、検索で再帰的にタグの子要素を辿るようになります。
デフォルトではTrueになってます。

tag = soup.find(class_='cow', recursive=True)  
print(tag.text)  
# six  

recursiveFalseにするとタグの子要素を再帰的に辿らなくなります。

tag = soup.find(class_='cow', recursive=False)  
print(tag)  
# None  

つまり第1階層のタグのみを取得できるということになります。

tag = soup.find('div', recursive=False)  
print(tag.name)  
# div  

おわりに

今回はBeautifulSoup4のfind()メソッドについて見てみました。
find()は利用頻度の高いメソッドと言えます。

🦝 < 探し物は何ですか?

🐭 < バイナリの中も、HTMLの中も・・・