Beautiful Soup とは
Python 標準の html.parser
モジュールは、SAX 形式のイベントドリブンなパーサなため、若干扱いにくいところがあります。
Beautiful Soup ライブラリを使用することで、HTML の要素に簡単にアクセスすることができるようになります。
Beautiful Soup パッケージは次のようにインストールできます。
$ pip install beautifulsoup4
HTML をパースする
最初に、HTML 文字列や HTML ファイルから bs4.BeautifulSoup
オブジェクトを生成する必要があります。
Beautiful Soup 自体には Web 上のリソースをダウンロードする機能は備わっていないので、そのようなケースでは、requests
モジュールなどで HTML リソースをダウンロードしておいて、BeautifulSoup
コンストラクタに渡してやります。
最初に登場する要素を見つける
BeautifulSoup
オブジェクトを生成したら、各要素の検索を行えるようになります。
一番簡単なのは、BeautifulSoup
オブジェクトのプロパティで HTML 要素のタグ名を指定する方法です。
次の例では、最初に登場する p
要素(bs4.element.Tag
オブジェクト)を取得しています。
from bs4 import BeautifulSoup
html_doc = """<html><body>
<h1>Title</h1>
<p class="foo">This is <b>bold</b> text.</p>
</body></html>
"""
soup = BeautifulSoup(html_doc, features="html.parser")
print(type(soup.p)) # => <class 'bs4.element.Tag'>
HTML 要素の Tag
オブジェクトを取得できたら、次のように直感的にその内容を参照できます。
print(soup.p) # => <p class="foo">This is <b>bold</b> text.</p>
print(soup.p.name) # => 'p'
print(soup.p.text) # => 'This is bold text.'
print(soup.p["class"]) # => ['foo']
print(soup.p.get("class")) # => ['foo']
属性値の取得方法には []
を使う方法と、get()
使う方法があることに注意してください。
指定した属性値が存在しない場合、[]
が KeyError
を発生させるのに対し、get()
は None
を返します。
いろいろな条件で要素を見つける
前述の例では、p
要素を参照するときに soup.p
のように記述していました。
その代わりに find
メソッドを使用すると、いろいろな条件で HTML 要素を検索することができます。
# 最初の p 要素
elem = soup.find("p")
# id 属性が sidebar である要素
elem = soup.find(id="sidebar")
# class 属性に comment を含む要素
elem = soup.find(class_=re.compile("comment"))
# href 属性に特定のドメイン名を含む a 要素
elem = soup.find("a", href=re.compile("^https://example.com/"))
class
キーワードは Python の予約語のため、HTML 要素の class 属性値を検索するには、末尾に _
の付いた class_
というパラメータ名を使用することに注意してください。
すでに find
メソッドによって見つけた要素がある場合は、その要素を基準にして子要素を検索することができます。
title = soup.find("head").find("title")
要素が見つからない場合、find
メソッドは None
を返します。
特定の条件に一致する要素をすべて見つける
指定したタグ名の要素をすべて取得するには、find_all
メソッドを使用します。
戻り値は、bs4.element.ResultSet
オブジェクトで、for
ループを使って見つかった要素を順番に処理できます。
次の例では、すべての a
要素を取得しています。
見つかった要素の属性は、attrs
プロパティで参照できます。
次の例では、HTML 内のすべての a
要素を検索し、その href
属性を出力しています。
links = soup.find_all("a")
for link in links:
if "href" in link.attrs:
print(link.text, ":", link.attrs["href"])
CSS セレクタによる要素の検索
find_all
の代わりに、select
メソッドを使用すると、CSS セレクタによる要素の検索を行えます。
elems = soup.select("a") # すべての a 要素
elems = soup.select("table tr") # table 要素以下の tr 要素
elems = soup.select(".hoge") # class 属性に hoge を含む要素
elems = soup.select("table.hoge") # class 属性に hoge を含む table 要素
elems = soup.select("#nav") # id 属性が nav である要素
elems = soup.select("#nav a") # id 属性が nav である要素以下の a 要素