Webスクレイピングでは、HTMLファイルをダウンロードし、そこからHTML要素を検索して情報を取得します。HTML要素を検索するには「CSSセレクタ」という表記方法を用います。

CSSセレクタは簡潔に記述できるので、ざっくりと要素を取り出して、後はPythonで細かな処理をすると簡単にスクレイピングをプログラミングできます。

本来、CSSセレクタはWebページのスタイルを指定するのに用いられます。デザインに用いるには、使い方に熟練を要しますが、スクレイピングでは先ほどのようにざっくりと検索できれば良いので、基本的な使い方を理解していれば大丈夫です。

そこで、今回はWebスクレイピングで「これだけ覚えておけば普通は不自由しないCSSセレクタの基本」をまとめました。ぜひ参考にしてください。

CSSセレクタ or XPath

要素を検索するにはXPathと呼ばれる言語を使うこともできますが、CSSセレクタの方が簡潔に書ける場合が多いです。さらに、BeautifulSoupでそのまま使用できるので、CSSセレクタの方がオススメです。

本ページの内容

基本セレクタ

覚えておきたい基本セレクタは以下の4つです。

分類 記述例 検索されるHTML要素
タイプセレクタ p すべてのp要素
li すべてのli要素
idセレクタ #miso id属性が「miso」である要素
classセレクタ .ramen class属性に「ramen」を含むすべての要素
.ramen.title class属性に「ramen」と「title」の両方を含むすべての要素
属性セレクタ [id=’syouyu’] id属性が「syouyu」である要素
[class=’ramen title’] class属性が「ramen title」であるすべての要素
[class*=’item’] class属性に「item」を含むすべての要素
[summary=’メニュー’] summary属性が「メニュー」であるすべての要素

実際にBeutiful Soup モジュールを使って試してみます。CSSセレクタでHTML要素を検索するには、Beutiful Soup モジュールを利用するのが定番です。

>>> from bs4 import BeautifulSoup
>>> html = """
<h3 class="ramen title" summary="メニュー">ラーメンメニュー</h3>
<ul>
  <li id="syouyu" class="ramen item">醤油ラーメン</li>
  <li id="miso" class="ramen item">味噌ラーメン</li>
</ul>
"""
>>> soup = BeautifulSoup(html, "html.parser")

Beutiful Soup モジュールでCSSセレクタを用いて検索するには、select()メソッドを使用します。マッチするすべての要素をリストで返します。該当する要素が無い場合は空リストを返します。

タイプセレクタ

>>> soup.select("li")[<li class="ramen item" id="syouyu">醤油ラーメン</li>, 
<li class="ramen item" id="miso">味噌ラーメン</li>]

idセレクタ

>>> soup.select("#miso")[<li class="ramen item" id="miso">味噌ラーメン</li>]

classセレクタ

>>> soup.select(".ramen")[<h3 class="ramen title">ラーメンメニュー</h3>, 
<li class="ramen item" id="syouyu">醤油ラーメン</li>, 
<li class="ramen item" id="miso">味噌ラーメン</li>]

属性セレクタ

>>> soup.select("[id='syouyu']")[<li class="ramen item" id="syouyu">醤油ラーメン</li>]
>>> soup.select("[class='ramen title']")[<h3 class="ramen title" summary="メニュー">ラーメンメニュー</h3>]

# 注意:全く同じ内容でないと一致しません
>>> soup.select("[class='title ramen']")
[]
>>> soup.select("[class*='item']")[<li class="ramen item" id="syouyu">醤油ラーメン</li>, 
<li class="ramen item" id="miso">味噌ラーメン</li>]
>>> soup.select("[summary='メニュー']")[<h3 class="ramen title" summary="メニュー">ラーメンメニュー</h3>]

セレクタの組み合わせ

属性による修飾

上記の「idセレクタ」「classセレクタ」「属性セレクタ」の3つは要素の末尾に追加して、要素を絞り込むことができます。

記述例 検索されるHTML要素
p#main-text id属性が「main-text」であるp要素
p.contents class属性に「contents」を含むすべてのp要素
li.ramen.item class属性に「ramen」と「item」を含むすべてのli要素
h3[summary=’メニュー’] summary属性が「メニュー」であるすべてのh3要素

class属性は上表の「li.ramen.item」のように数珠つなぎに連結できます。

子孫・子セレクタ

A Bのように「スペース」を挟んで連結した場合は、A要素の階層下のB要素すべてを取得します(=子孫すべて)。

A > Bのように「>」を挟んだ場合は、A要素の直下のすべてのB要素を取得します(=子だけ)。

記述例 検索されるHTML要素
div p div要素の階層下のすべてのp要素
div#main p id属性が「main」であるdiv要素の階層下のすべてのp要素
div > p div要素の直下のすべてのp要素
div#main > p id属性が「main」であるdiv要素の直下のすべてのp要素

上表の「div#main p」のように、属性による修飾も併用できます。

グループ化

複数の要素を一度に検索する場合は、以下のように「,」(カンマ)で繋ぎます。

例えば、以下のコードでは、すべてのh3要素とli要素を一度に検索します。

>>> soup.select("h3, li")[<h3 class="ramen title" summary="メニュー">ラーメンメニュー</h3>, 
<li class="ramen item" id="syouyu">醤油ラーメン</li>, 
<li class="ramen item" id="miso">味噌ラーメン</li>]

以下の場合は、id属性が「syouyu」と「miso」の要素を一度に検索します。

>>> soup.select("#syouyu, #miso")[<li class="ramen item" id="syouyu">醤油ラーメン</li>, 
<li class="ramen item" id="miso">味噌ラーメン</li>]

CSS(+HTML)は、以下のようにコンパクトにまとまった書籍が1冊手元にあるとすぐ調べられて何かと便利です。