Pythonを使用したWebスクレイピングやブラウザ自動操作において、Seleniumで目的の要素を正確に特定することは非常に重要です。
モダンなWebサイトでは、1つのHTML要素に複数のクラスが付与されていることが一般的であり、それらを適切に指定するスキルが求められます。
CSSセレクタを活用すれば、複雑な要素もシンプルかつ高速に抽出することが可能になります。
本記事では、SeleniumでCSSセレクタを使用して複数クラスを指定する具体的な書き方を、AND条件とOR条件に分けて解説します。
SeleniumでCSSセレクタを利用するメリット
Seleniumで要素を指定する方法には、ID、Name、XPath、CSSセレクタなど複数の選択肢があります。
その中でも、CSSセレクタは処理速度が速く、記述が簡潔であるという大きなメリットを持っています。
特に複数のクラスを組み合わせる場合、XPathよりも可読性が高く、保守しやすいコードを書くことができます。
また、多くのフロントエンドエンジニアがスタイル定義でCSSセレクタを利用しているため、学習コストが低い点も魅力です。
最新のブラウザ自動化においては、CSSセレクタを第一選択肢として考えるのがベストプラクティスと言えるでしょう。
基本的なCSSセレクタの記述法
まずは、単一のクラスを指定する基本を確認しておきましょう。
HTMLでclass="example"という属性を持つ要素を指す場合、CSSセレクタでは.exampleと記述します。
SeleniumのPythonコードでは、By.CSS_SELECTORを使用して要素を取得します。
from selenium import webdriver
from selenium.webdriver.common.by import By
# ブラウザの起動
driver = webdriver.Chrome()
# 単一クラスを指定して要素を取得
element = driver.find_element(By.CSS_SELECTOR, ".example")
複数クラスのAND条件指定(すべてのクラスを持つ)
特定の要素が「クラスA」と「クラスB」の両方を持っている場合に、それらを絞り込んで指定する方法を解説します。
これは「AND条件」と呼ばれ、クラス名をつなげて記述することで実現します。
ドットでクラスをつなげる書き方
例えば、class="button primary large"という3つのクラスを持つ要素があるとします。
この要素を特定するには、.button.primary.largeという形式でセレクタを記述します。
重要なポイントは、クラス名の間にスペースを入れないことです。
スペースを入れてしまうと、「子孫要素」を指す別の意味になってしまうため注意が必要です。
# class="btn active" の両方を持つ要素を取得する場合
# 正解:ドットを連続させる
target = driver.find_element(By.CSS_SELECTOR, ".btn.active")
# 不正解:スペースを入れると「btnクラスの中にあるactiveクラスを持つ子要素」になる
# target = driver.find_element(By.CSS_SELECTOR, ".btn .active")
タグ名と複数クラスの組み合わせ
クラス名だけでなく、タグ名も組み合わせて指定することで、より確実に要素を特定できます。
例えば、divタグであり、かつ複数のクラスを持つ要素を指定する場合は、div.class1.class2のように記述します。
これにより、同じクラス名を持つ他のタグ(例えばspanなど)を除外することができます。
# divタグで、かつ class="item selected" を持つ要素を指定
item = driver.find_element(By.CSS_SELECTOR, "div.item.selected")
複数クラスのOR条件指定(いずれかのクラスを持つ)
次に、「クラスA」または「クラスB」のいずれかを持つ要素をすべて取得する方法について解説します。
これは「OR条件」と呼ばれ、複数のセレクタをカンマ(,)で区切って記述することで実現できます。
カンマ区切りによる複数要素の抽出
例えば、警告メッセージを表す.errorクラスと、成功メッセージを表す.successクラスの両方を一度に取得したい場合があります。
この場合、.error, .successと記述することで、どちらかのクラスを持つすべての要素をリストとして取得できます。
# error または success クラスを持つ要素をすべて取得
messages = driver.find_elements(By.CSS_SELECTOR, ".error, .success")
for msg in messages:
print(msg.text)
この手法は、複数の異なるステータスを持つ要素をまとめて操作したい場合に非常に便利です。
属性セレクタを用いた柔軟なクラス指定
CSSセレクタには、クラス名の一部が一致する場合や、特定の文字列で始まる場合を指定する「属性セレクタ」も存在します。
動的にクラス名が変わるWebサイトや、共通の接頭辞を持つクラスをまとめて扱いたい場合に有効です。
部分一致・前方一致・後方一致の使い分け
属性セレクタでは、[class*="value"]のような特殊な記号を使用します。
| 記法 | 意味 | 使用例 |
|---|---|---|
[class="val"] | 完全一致 | クラス属性が”val”のみに一致 |
[class~="val"] | 単語一致 | スペース区切りのクラス群に”val”が含まれる |
[class^="val"] | 前方一致 | クラス属性が”val”から始まる |
[class$="val"] | 後方一致 | クラス属性が”val”で終わる |
[class*="val"] | 部分一致 | クラス属性の中に”val”が含まれる |
特に部分一致(*=)は、フレームワークが自動生成するランダムな文字列を含むクラスを避けて指定する際に重宝します。
# クラス名の中に "nav-" という文字列を含む要素を取得
nav_elements = driver.find_elements(By.CSS_SELECTOR, "[class*='nav-']")
実践例:複数クラス指定の使い分け
ここでは、具体的なHTML構造を例に、どのようにCSSセレクタを使い分けるかを実演します。
以下のようなHTML構造を想定してください。
<div class="container">
<button class="btn primary active">保存</button>
<button class="btn secondary">キャンセル</button>
<p class="text-info status-ok">完了しました</p>
</div>
複雑な組み合わせの指定方法
この中で「保存」ボタンだけをピンポイントで取得したい場合、AND条件を使用するのが最適です。
.btn.primary.activeと指定すれば、他のボタンと混同することなく取得できます。
一方、すべてのボタンを取得したい場合は、単に.btnと指定するか、.primary, .secondaryのようにOR条件を利用します。
# AND条件で特定のボタンを取得
save_btn = driver.find_element(By.CSS_SELECTOR, ".btn.primary.active")
print(f"取得したボタン: {save_btn.text}")
# OR条件でメッセージとボタンをまとめて取得
elements = driver.find_elements(By.CSS_SELECTOR, ".btn, .text-info")
for el in elements:
print(f"要素テキスト: {el.text}")
取得したボタン: 保存
要素テキスト: 保存
要素テキスト: キャンセル
要素テキスト: 完了しました
よくある間違いと注意点
CSSセレクタで複数クラスを指定する際に、初心者が陥りやすいミスがいくつかあります。
それらをあらかじめ把握しておくことで、デバッグの時間を大幅に短縮できます。
1. クラス名の順番に依存しない
HTML上での記述がclass="A B"であっても、CSSセレクタで.B.Aと記述して問題なく動作します。
CSSセレクタのAND指定は順不同であり、指定したすべてのクラスが含まれていれば一致とみなされます。
2. スペースの有無による意味の違い
先述の通り、ドットの間にスペースを入れると、構造的な親子関係を指すことになります。
.class1.class2(スペースなし)は「同じ要素が両方のクラスを持つ」ことを意味します。
.class1 .class2(スペースあり)は「class1を持つ要素の中にある、class2を持つ子孫要素」を意味します。
この違いを正しく理解していないと、意図しない要素を取得したり、要素が見つからずエラーになったりします。
3. 特殊文字のエスケープ
クラス名にコロン(:)やドット(.)自体が含まれている特殊なケースでは、バックスラッシュによるエスケープが必要です。
ただし、Selenium経由で指定する場合はエスケープ処理が複雑になるため、可能な限り属性セレクタ([class="..."])で代用することを推奨します。
XPathとの使い分け基準
複数クラスの指定はXPathでも可能ですが、記述が非常に冗長になります。
例えば、.class1.class2と同じことをXPathで表現すると、//*[contains(concat(' ', normalize-space(@class), ' '), ' class1 ') and contains(concat(' ', normalize-space(@class), ' '), ' class2 ')]となります。
一目瞭然ですが、CSSセレクタの方が圧倒的に読みやすく、書き間違いも少なくなります。
ただし、「特定のテキストを含む要素の親に移動する」といった複雑な階層移動が必要な場合は、XPathを利用せざるを得ません。
基本はCSSセレクタを使い、CSSセレクタで不可能な場合のみXPathを使うという方針が、クリーンなコードを保つコツです。
まとめ
PythonとSeleniumを組み合わせたブラウザ自動化において、CSSセレクタでの複数クラス指定は必須のテクニックです。
AND条件はドットをつなげて記述し、OR条件はカンマで区切って記述するという基本ルールをマスターしましょう。
また、属性セレクタを活用することで、動的なクラス名にも柔軟に対応できるようになります。
XPathと比較してシンプルで高速なCSSセレクタを使いこなすことで、スクレイピングの精度とメンテナンス性は格段に向上します。
今回紹介した書き方を参考に、より効率的な自動化プログラムを構築してみてください。
