PythonでWebスクレイピングを行う際、BeautifulSoupライブラリは非常に強力なツールとなります。
特定の情報を抽出する際に、一つのタグだけでなく複数の異なるタグを同時に取得したい場面は多々あります。
例えば、記事の見出しと本文をセットで取得したい場合や、リンクと画像タグを並び順通りに抽出したい場合などです。
この記事では、BeautifulSoupのfind_allメソッドを活用して、効率的に複数のタグを一度に抽出する具体的な手法を紹介します。
基本的な使い方から応用的なフィルタリングまでを網羅しているため、実務でのデータ収集に役立ててください。
find_allで複数のタグを指定する基本操作
BeautifulSoupのfind_allメソッドは、引数にリストを渡すことで複数のタグを一度に検索できます。
通常、soup.find_all('p')のように文字列を指定すると特定のタグのみを取得しますが、['h1', 'p']のように記述すると両方のタグが対象になります。
リスト形式によるタグの指定
最もシンプルで直感的な方法は、抽出したいタグ名をリストに格納して引数に渡すことです。
この方法を使用すると、HTML内で出現した順番を維持したまま、指定したすべてのタグを取得できます。
from bs4 import BeautifulSoup
html_doc = """
<div>
<h1>メインタイトル</h1>
<p>最初の段落です。</p>
<h2>サブタイトル</h2>
<p>二番目の段落です。</p>
</div>
"""
soup = BeautifulSoup(html_doc, 'html.parser')
# h1タグとh2タグを一度に抽出する
tags = soup.find_all(['h1', 'h2'])
for tag in tags:
print(f"Tag: {tag.name}, Text: {tag.get_text()}")
Tag: h1, Text: メインタイトル
Tag: h2, Text: サブタイトル
上記のコードでは、h1とh2の両方がリストとして取得されていることがわかります。
この手法は、特定の構造を持つWebページから情報を一括で抜き出す際に非常に便利です。
正規表現を利用した複数タグの抽出
タグ名が特定のパターンを持っている場合、正規表現(Regular Expression)を使用するのが効率的です。
例えば、h1からh6までのすべての見出しタグを抽出したい場合に有効です。
import re
from bs4 import BeautifulSoup
html_content = """
<section>
<h1>章のタイトル</h1>
<h2>節のタイトル</h2>
<h3>項のタイトル</h3>
</section>
"""
soup = BeautifulSoup(html_content, 'html.parser')
# 正規表現を使ってh1からh6までをマッチさせる
heading_tags = soup.find_all(re.compile('^h[1-6]'))
for heading in heading_tags:
print(heading.name)
h1
h2
h3
re.compile('^h[1-6]')を使用することで、hで始まり1から6の数字が続くすべてのタグにマッチさせることができます。
一つずつリストに書き出す手間が省けるため、対象が多い場合に推奨される手法です。
属性条件を組み合わせた複数タグの抽出
タグの種類だけでなく、特定のクラス名やIDを持つ複数の要素を抽出したいケースもあります。
find_allでは、タグ名のリスト指定と同時に辞書形式の属性指定を組み合わせることが可能です。
複数のタグに共通するクラスを指定する
例えば、divタグとspanタグの両方のうち、特定のクラスを持つものだけを抽出したい場合です。
from bs4 import BeautifulSoup
html_data = """
<div class="highlight">重要なニュース</div>
<p class="content">通常の内容</p>
<span class="highlight">注目のキーワード</span>
"""
soup = BeautifulSoup(html_data, 'html.parser')
# highlightクラスを持つdivとspanを抽出
elements = soup.find_all(['div', 'span'], class_='highlight')
for el in elements:
print(f"Tag: {el.name}, Content: {el.string}")
Tag: div, Content: 重要なニュース
Tag: span, Content: 注目のキーワード
このように、第一引数にリストを、第二引数にキーワード引数を指定することで、絞り込みの精度を上げることができます。
関数を用いた高度なフィルタリング
より複雑な条件が必要な場合は、find_allに真偽値を返す関数を渡すことができます。
関数を使用すれば、タグ名、テキスト内容、属性の有無などを自由に組み合わせて判断できます。
from bs4 import BeautifulSoup
html_snippet = """
<ul>
<li id="first">項目1</li>
<li class="special">項目2</li>
<p class="special">追加の説明</p>
</ul>
"""
soup = BeautifulSoup(html_snippet, 'html.parser')
# classが'special'であるか、idが'first'であるタグを抽出する関数
def complex_filter(tag):
return tag.has_attr('class') and 'special' in tag.get('class') or tag.get('id') == 'first'
results = soup.find_all(complex_filter)
for item in results:
print(f"Found: {item.name} with text: {item.text}")
Found: li with text: 項目1
Found: li with text: 項目2
Found: p with text: 追加の説明
関数による指定は非常に柔軟であり、動的に変化するWebサイトの構造を解析する際に真価を発揮します。
抽出方法の比較まとめ
複数のタグを抽出する方法には、主に以下の3つのアプローチがあります。
用途に応じて最適な方法を選択してください。
| 手法 | 特徴 | おすすめのケース |
|---|---|---|
| リスト形式 | 記述が簡単で直感的。 | 抽出したいタグが明確に決まっている場合。 |
| 正規表現 | パターンで一括指定可能。 | 見出し(h1-h6)など名前が似ている場合。 |
| 関数指定 | 最も柔軟な条件設定が可能。 | 属性や階層など複雑な条件が絡む場合。 |
よくあるエラーと注意点
複数タグの抽出を試みる際、いくつかの注意点があります。
一つ目は、find_allが返す結果はリスト形式(ResultSet)であるという点です。
取得した結果に対して直接.textや.get_text()を呼び出すことはできません。
必ずforループなどで個別の要素を取り出してから、各要素に対して操作を行う必要があります。
二つ目は、取得される順番についてです。
find_all(['h1', 'p'])と記述した場合、h1が先に見つかればh1が、pが先に見つかればpが取得されます。
リストの引数の順番(h1が先かpが先か)は、取得される順番には影響しないことに留意してください。
要素は常にHTMLソースコード内に出現する順序に従って取得されます。
まとめ
PythonのBeautifulSoupにおいて、find_allで複数のタグを一度に抽出する方法は非常に多岐にわたります。
基本的なリスト形式の指定をマスターするだけで、多くのスクレイピング作業は大幅に簡略化されます。
より高度なスクレイピングが必要な場合は、正規表現や関数を用いたフィルタリングを試してみてください。
これらのテクニックを組み合わせることで、複雑なHTML構造から必要なデータだけを的確に抜き出すことが可能になります。
効率的なデータ収集を行い、分析や開発に役立てていきましょう。
