Python

BeautifulSoupとは?インストールから基本的な使い方・スクレイピングまで解説

BeautifulSoup(ビューティフルスープ/bs4)とは、PythonでHTMLやXMLを解析(パース)し、必要なデータを抽出できるライブラリです。Webページのソースから、タイトル・リンク・特定のタグや文章などを、わかりやすい書き方で取り出せます。Webスクレイピング(Webページからのデータ収集)で広く使われており、初心者にも扱いやすいのが特徴です。スクレイピングそのものの仕組みや、クローリング・APIとの違い、法務上の注意点はスクレイピングとは何かを整理した解説記事で扱っています。本記事では、インストール方法、find・find_all・selectといった基本的な使い方、requestsと組み合わせたスクレイピングの実践、そして利用上の注意点を、わかりやすく解説します。

BeautifulSoupとは

BeautifulSoupは、HTMLの文字列を「プログラムで扱える形」に変換し、タグや属性を指定して目的の要素を取り出せるようにするライブラリです。たとえば「ページ内のすべてのリンク」「特定のクラスを持つ見出し」などを、数行のコードで抽出できます。

HTMLを直接文字列処理するのは大変ですが、BeautifulSoupを使えば、タグの階層構造をたどって直感的にデータを取得できます。通常は、Webページを取得するrequestsライブラリと組み合わせて使います。requestsでHTMLを取ってきて、BeautifulSoupで解析する、という流れが基本です。

BeautifulSoupのインストール

BeautifulSoupは、pipでインストールします。パッケージ名は「beautifulsoup4」です。

pip install beautifulsoup4

注意点として、「beautifulsoup4」と正確に指定してください。「beautifulsoup」とだけ書くと古いBeautifulSoup3が入ってしまうことがあり、これはPython 3系では正しく動作しません。あわせて、Webページを取得するためのrequestsもインストールしておきます。

pip install requests

必要に応じて、高速なパーサであるlxmlも入れておくと便利です(後述)。

pip install lxml

パーサの種類

BeautifulSoupでHTMLを解析するときは、「パーサ(解析器)」を指定します。代表的なものは次の3つです。

  • html.parser:Python標準で追加インストール不要。手軽に使え、基本的にはこれで十分です。
  • lxml:高速で、多少崩れたHTMLにも対応しやすい。大量に処理する場合に向きます(別途インストールが必要)。
  • html5lib:壊れたHTMLにもっとも強いが、動作は遅め(別途インストールが必要)。

迷ったら、まずは標準のhtml.parserを使えば問題ありません。

BeautifulSoupの基本的な使い方

BeautifulSoupの基本は、HTMLを読み込んでBeautifulSoupオブジェクトを作り、そこからメソッドで要素を取り出すことです。次のサンプルHTMLで見ていきます。

from bs4 import BeautifulSoup

html_doc = """
<html><head><title>サンプルページ</title></head>
<body>
<p class="story">むかしむかし、3姉妹がいました。
<a href="http://example.com/1" class="sister" id="link1">エルシー</a>、
<a href="http://example.com/2" class="sister" id="link2">レイシー</a>。
</p>
</body></html>
"""

soup = BeautifulSoup(html_doc, 'html.parser')

タグや文字列を取得する

タグ名を指定すると、最初に見つかった要素を取得できます。.stringでタグ内の文字列を取り出せます。

# titleタグの中の文字列を取得
print(soup.title.string)   # サンプルページ

# 最初のaタグを取得(soup.find('a') と同じ)
print(soup.a)

# リンク先(href属性)を取得
print(soup.a.get('href'))  # http://example.com/1

find と find_all

もっともよく使うのがfindfind_allです。findは条件に合う最初の1つfind_allすべてを取得します。

# 最初のaタグ
first_link = soup.find('a')

# すべてのaタグを取得して、リンク先を順に表示
for link in soup.find_all('a'):
    print(link.get('href'))

クラスや属性で絞り込むこともできます。クラスを指定するときは、Pythonの予約語classと区別するためclass_(末尾にアンダースコア)を使う点に注意します。

# class="story" のpタグをすべて取得
soup.find_all('p', class_='story')

# id="link1" の要素を取得
soup.find(id='link1')

select(CSSセレクタ)

CSSセレクタで指定したい場合はselect(すべて取得)とselect_one(最初の1つ)を使います。普段からCSSに慣れている人には直感的です。

# CSSセレクタで取得
soup.select_one('title')      # 最初のtitle
soup.select('p.story a')      # p.story の中のaタグをすべて
soup.select('#link1')         # id="link1"

このように、find系(タグ・属性で指定)select系(CSSセレクタで指定)の2通りがあり、好みや状況に応じて使い分けられます。

requestsと組み合わせたスクレイピングの実践

実際のWebページを対象にする場合は、requestsでHTMLを取得し、それをBeautifulSoupで解析します。基本の流れは次の通りです。

import requests
from bs4 import BeautifulSoup

url = 'https://example.com'
res = requests.get(url)
res.raise_for_status()  # 取得に失敗したらエラーにする

soup = BeautifulSoup(res.text, 'html.parser')

# ページ内のすべてのリンクのテキストとURLを取得
for a in soup.find_all('a'):
    text = a.get_text(strip=True)
    href = a.get('href')
    print(text, href)

取得したデータは、CSVファイルなどに保存して活用できます。集計や加工をしたい場合は、データ分析ライブラリのpandasと組み合わせると、表形式での整形や分析がしやすくなります。

import csv

rows = []
for a in soup.find_all('a'):
    rows.append([a.get_text(strip=True), a.get('href')])

with open('links.csv', 'w', newline='', encoding='utf-8') as f:
    writer = csv.writer(f)
    writer.writerow(['text', 'url'])
    writer.writerows(rows)

記事本文のように特定の場所だけ取りたい場合は、その部分を囲んでいるタグやクラスを指定します。ブラウザの「開発者ツール」でHTML構造を確認し、対象のタグ・クラスを調べるのが実践のコツです。

なお、JavaScriptで後から内容が描画されるページは、requestsで取得したHTMLには目的のデータが含まれないことがあります。その場合は、ブラウザを自動操作してページを描画させるSeleniumでHTMLを取得し、それをBeautifulSoupで解析する、という組み合わせが有効です。

# 例:本文がある領域を指定して、段落テキストをまとめて取得
body = soup.find('div', class_='article-content')
if body:
    text = "\n".join(p.get_text() for p in body.find_all('p'))
    print(text)

BeautifulSoupを使う際の注意点

スクレイピングは便利ですが、ルールとマナーを守って行う必要があります。次の点に注意しましょう。

  • 利用規約・robots.txtを確認する:対象サイトがスクレイピングを禁止していないかを必ず確認します。公式のAPIが用意されている場合は、そちらを優先します。
  • サーバーに負荷をかけない:短時間に大量のリクエストを送らないよう、アクセスの間隔をあけます(例:time.sleep(1)で1秒待つ)。
  • 著作権・個人情報に配慮する:取得したデータの利用目的が、著作権や個人情報保護の観点で問題ないかを確認します。
  • HTML構造の変化に備える:Webページの構造は変わることがあります。要素が取得できなかった場合(Noneが返る場合)に備えて、エラー処理を入れておくと安定します。
import time

urls = ['https://example.com/page1', 'https://example.com/page2']
for url in urls:
    res = requests.get(url)
    soup = BeautifulSoup(res.text, 'html.parser')
    # ここで解析処理
    time.sleep(1)  # 1秒あけて次のリクエストへ

まとめ

BeautifulSoupの要点を整理します。

  • BeautifulSoup(bs4)とは、PythonでHTML/XMLを解析しデータを抽出できるライブラリ
  • インストールは pip install beautifulsoup4(「beautifulsoup4」と正確に指定)。requestsと組み合わせて使う
  • パーサは標準のhtml.parserでOK。高速処理ならlxml
  • 基本はfindfind_all(タグ・属性)とselectselect_one(CSSセレクタ)。クラス検索はclass_
  • スクレイピングは利用規約・robots.txtの確認、アクセス間隔、著作権・個人情報への配慮を忘れずに

BeautifulSoupは、Webからのデータ収集を手軽に実現できる強力なツールです。まずは標準のhtml.parserで、身近なページのタイトルやリンクを取得することから始めてみましょう。

よくある質問(FAQ)

Q. BeautifulSoupのインストールでエラーになります。
A. パッケージ名は「beautifulsoup4」です。pip install beautifulsoup4と正確に指定してください。「beautifulsoup」だと古いバージョン(Python 3非対応)が入ることがあります。

Q. findとfind_allの違いは?
A. findは条件に合う最初の1つ、find_allは条件に合うすべての要素をリストで返します。

Q. クラスで要素を探すときの書き方は?
A. classはPythonの予約語のため、末尾にアンダースコアを付けたclass_を使います。例:soup.find_all('p', class_='story')

Q. パーサは何を選べばいいですか?
A. 標準のhtml.parserで十分です。大量に処理して速度が欲しい場合や、崩れたHTMLを扱う場合はlxmlやhtml5libを検討します。

Q. スクレイピングは自由に行ってよいですか?
A. 対象サイトの利用規約やrobots.txtを確認し、禁止されていないかを必ずチェックしてください。アクセス間隔をあけて負荷をかけないこと、著作権や個人情報に配慮することも重要です。

資料請求

RELATED POSTS 関連記事