閉じる

Python Beautiful Soupで複数クラスをAND検索する方法:find_allとselectの使い分け

PythonでWebスクレイピングを行う際、目的のデータを正確に抽出することは最も重要な工程の一つです。

Webサイトの構造が複雑化している現代では、一つのHTMLタグに複数のCSSクラスが割り当てられているケースが珍しくありません。

特定のクラスを持つ要素だけを絞り込みたい場合、単純な検索ではなく「クラスAとクラスBの両方を持つ」というAND検索のテクニックが必要になります。

Beautiful Soupには複数の検索手法が用意されていますが、記述方法によって動作や柔軟性が大きく異なります。

本記事では、複数クラスを指定したAND検索について、主要な2つのメソッドであるfind_allselectの使い分けを中心に詳しく紹介します。

複数クラスを指定したAND検索が必要な理由

現代のフロントエンド開発において、Tailwind CSSやBootstrapといったCSSフレームワークの普及により、HTMLタグには多くのクラスが付与されるようになりました。

例えば、単にclass="item"という指定だけでは、広告パーツや関連記事など、本来取得したくない要素までヒットしてしまうことがあります。

そこで、「商品リストの中にある(item)」「現在セール中の(sale)」という2つの条件を満たす要素のみを抽出するといった絞り込みが不可欠です。

AND検索をマスターすることで、ノイズの少ない綺麗なデータを効率的に収集できるようになります。

また、スクレイピングのコードがシンプルになり、後からのメンテナンス性も向上するというメリットがあります。

find_allメソッドで複数クラスをAND検索する方法

Beautiful Soupの最も基本的なメソッドであるfind_allでも、複数クラスのAND検索は可能です。

ただし、記述方法を誤ると「いずれかのクラスを含む(OR検索)」になってしまうため注意が必要です。

attrs引数にリストを指定する場合の注意点

find_allの第二引数やclass_引数にリストを渡すと、デフォルトではOR検索(いずれかのクラスに合致)として処理されます。

以下のコードは、AND検索ではなくOR検索の結果を返します。

Python
from bs4 import BeautifulSoup

html = """
<div class="content active">ターゲット</div>
<div class="content">対象外1</div>
<div class="active">対象外2</div>
"""
soup = BeautifulSoup(html, "html.parser")

# これはOR検索になるため、3つのdivすべてが取得される可能性があります
elements = soup.find_all("div", class_=["content", "active"])
for el in elements:
    print(el.text)
実行結果
ターゲット
対象外1
対象外2

文字列として完全に一致させる方法

HTML内のクラスの並び順が固定されている場合は、文字列として複数クラスを記述することでAND検索のような挙動を実現できます。

Python
# クラスの順序が完全に一致している必要がある
elements = soup.find_all("div", class_="content active")

しかし、この方法はクラスの順番が入れ替わったり、間に別のクラスが入ったりすると抽出に失敗するため、堅牢なスクレイピングとは言えません。

関数(ラムダ式)を利用した厳格なAND検索

find_allで確実なAND検索を行うには、要素を判定する関数を引数に渡す方法が有効です。

Python
# contentとactiveの両方を保持している要素のみを抽出
elements = soup.find_all(lambda tag: tag.name == "div" and 
                         set(["content", "active"]).issubset(tag.get("class", [])))

for el in elements:
    print(el.text)
実行結果
ターゲット

この方法であれば、クラスの順番に関わらず、指定したすべてのクラスが含まれている要素だけを正確に取得できます。

selectメソッド(CSSセレクタ)によるAND検索

Beautiful Soupにおいて、複数クラスのAND検索を行う最も推奨される方法はselectメソッドの使用です。

selectメソッドはCSSセレクタを利用するため、Web制作に馴染みのある直感的な記述が可能です。

ドット繋ぎによるAND検索の記述

CSSのルールに従い、クラス名の先頭にドット(.)を付け、それらをスペースを入れずに連結させることでAND条件となります。

例えば、contentクラスとactiveクラスの両方を持つ要素を探す場合は、.content.activeと記述します。

Python
from bs4 import BeautifulSoup

html = """
<div class="item sale primary">セール対象</div>
<div class="item primary">通常商品</div>
<div class="sale">バナーのみ</div>
"""
soup = BeautifulSoup(html, "html.parser")

# itemクラスとsaleクラスを両方持つ要素を抽出
results = soup.select(".item.sale")

for res in results:
    print(res.text)
実行結果
セール対象

この記述方法の優れた点は、HTML上のクラスの順序に依存しないことです。

class="item sale"であってもclass="sale item"であっても、正しくヒットします。

タグ名との組み合わせ

特定のタグに限定してAND検索を行いたい場合は、タグ名の直後にクラスを繋げます。

Python
# divタグであり、かつitemとsaleの両方のクラスを持つ
results = soup.select("div.item.sale")

これにより、同じクラス名を持つ他のタグ(例えばspanタグなど)を除外して抽出することが可能になります。

find_allとselectの使い分け比較

どちらのメソッドを使用すべきか迷った際のために、それぞれの特徴を比較表にまとめました。

比較項目find_allselect (CSSセレクタ)
AND検索の書きやすさ関数定義が必要でやや複雑非常に直感的で簡単
クラスの順序依存文字列指定時は依存する依存しない
処理速度わずかに高速な傾向があるfind_allに比べると僅かに遅い
柔軟性Pythonのロジックを組み込みやすいCSSの高度な指定が可能

結論として、複数クラスのAND検索が目的であれば、selectメソッドを使用するのがベストプラクティスと言えます。

コードの可読性が高く、CSSの知識をそのまま転用できるため、開発効率が劇的に向上します。

実践的なコード例:多条件でのフィルタリング

より実用的なシーンとして、複雑な条件を組み合わせたスクレイピングの例を見ていきましょう。

ここでは、特定のカテゴリに属し、かつ在庫がある商品のみを抽出するコードを想定します。

Python
html_doc = """
<ul id="product-list">
    <li class="product electronics available">スマートフォン - 在庫あり</li>
    <li class="product electronics soldout">ノートPC - 売り切れ</li>
    <li class="product books available">Python教本 - 在庫あり</li>
    <li class="ad-banner electronics">広告:最新ガジェット</li>
</ul>
"""
soup = BeautifulSoup(html_doc, "html.parser")

# 1. electronicsカテゴリで在庫がある(available)商品(product)のみをAND検索
target_products = soup.select("li.product.electronics.available")

print("--- 抽出結果 ---")
for product in target_products:
    print(product.get_text())
実行結果
--- 抽出結果 ---
スマートフォン - 在庫あり

このように、3つ以上のクラスが絡む場合でも、ドットで繋ぐだけで簡単に絞り込みが可能です。

また、親要素のIDと組み合わせることで、特定のエリア内にある要素のみを対象とするさらに精密な抽出も行えます。

Python
# product-listというIDの中にある、特定クラスの要素を探す
results = soup.select("#product-list .product.available")

複数クラス検索でよくある落とし穴と対処法

実装時に陥りやすいミスとその解決策についても知っておく必要があります。

クラス名のスペルミスと動的クラス

スクレイピング対象のサイトがReactやVue.jsなどのフレームワークで構築されている場合、クラス名が動的に生成されることがあります。

例えば、jsc-12345のようなランダムな文字列が含まれるクラスは、再読み込みのたびに変わる可能性があります。

このような場合は、AND検索に含めるクラスを「不変なもの」だけに絞るか、部分一致(正規表現)を検討してください。

スペースの有無による挙動の違い

select(".class1 .class2")のようにドットの間にスペースを入れてしまうと、「class1を持つ要素の子孫にあるclass2を持つ要素」という意味に変わってしまいます。

同一タグ内の複数クラスを指す場合は、必ず.class1.class2とスペースなしで記述することを徹底してください。

Beautiful Soupのバージョンによる差異

非常に古いバージョンのBeautiful Soupを使用している場合、CSSセレクタのサポートが不完全なことがあります。

2026年現在のモダンな環境であれば問題ありませんが、環境構築時には最新のbeautifulsoup4がインストールされているか確認しましょう。

まとめ

PythonのBeautiful Soupを用いて複数クラスをAND検索する方法について解説しました。

find_allメソッドでもラムダ式を活用すればAND検索は可能ですが、より簡潔で直感的に記述できるselectメソッド(CSSセレクタ)の利用が最も効率的です。

.class1.class2のようにドットで繋ぐ記述法を覚えるだけで、複雑なHTML構造から目的のデータをピンポイントで抽出できるようになります。

スクレイピングの精度を高めるためには、対象サイトのHTMLを事前によく観察し、どのクラスの組み合わせがユニーク(一意)であるかを見極めることが成功の鍵となります。

今回紹介した手法を組み合わせて、ぜひ高度なデータ収集に役立ててください。

URLをコピーしました!