Python BeautifulSoupの使い方完全ガイド!Webスクレイピング入門【2025年最新版】

 

WebスクレイピングでHTMLを解析したいけど、どのライブラリを使えばいいか迷っていませんか?Python BeautifulSoupは、HTMLやXMLの解析において最も人気が高く、初心者にも使いやすいライブラリです。この記事では、BeautifulSoupの基本的な使い方から実践的なWebスクレイピング手法まで、分かりやすく解説します。

Python BeautifulSoupとは?できることを解説

BeautifulSoupは、HTMLやXMLドキュメントを解析するためのPythonライブラリです。Webページから特定の情報を抽出したり、データを構造化したりする際に威力を発揮します。

BeautifulSoupでできること

  • Webスクレイピング: ニュースサイトや商品情報の自動収集
  • HTML解析: Webページの構造分析
  • データ抽出: 特定のタグやクラスから情報を取得
  • XML処理: RSS feedやAPI レスポンスの解析

Python BeautifulSoupのインストール方法

BeautifulSoupとHTTPリクエストに必要なrequestsライブラリをインストールします。

pip install beautifulsoup4 requests lxml

lxmlは高速なXMLパーサーとして推奨されています。

【基本編】BeautifulSoupの使い方

1. 基本的なHTML解析

from bs4 import BeautifulSoup
import requests

# Webページを取得
url = "https://httpbin.org/html"
response = requests.get(url)
soup = BeautifulSoup(response.content, 'html.parser')

# タイトルを取得
print(soup.title.text)  # ページタイトル
print(soup.find('h1').text)  # 最初のh1タグ

2. 要素の検索方法

from bs4 import BeautifulSoup

html = """
<html>
<body>
<div class="content">
<p id="first">最初の段落</p>
<p class="highlight">ハイライト段落</p>
<a href="https://example.com">リンク</a>
</div>
</body>
</html>
"""

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

# IDで検索
first_p = soup.find('p', id='first')
print(first_p.text)

# クラスで検索
highlight = soup.find('p', class_='highlight')
print(highlight.text)

# 複数要素を取得
all_p = soup.find_all('p')
for p in all_p:
    print(p.text)

3. CSSセレクターの使用

from bs4 import BeautifulSoup

html = """
<div class="container">
<div class="item">アイテム1</div>
<div class="item special">アイテム2</div>
<ul>
<li>リスト1</li>
<li>リスト2</li>
</ul>
</div>
"""

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

# CSSセレクターで検索
items = soup.select('.item')  # クラス名で検索
special = soup.select('.item.special')  # 複数クラス
first_li = soup.select('ul li:first-child')  # 擬似セレクター

for item in items:
    print(item.text)

【実践編】BeautifulSoupを使ったWebスクレイピング

ニュースサイトの見出し取得

from bs4 import BeautifulSoup
import requests

def get_news_headlines(url):
    response = requests.get(url)
    soup = BeautifulSoup(response.content, 'html.parser')
    
    # 見出しを取得(サイトに応じて調整)
    headlines = soup.find_all('h2', class_='headline')
    
    for i, headline in enumerate(headlines[:5], 1):
        print(f"{i}. {headline.text.strip()}")

# 使用例
get_news_headlines("https://example-news.com")

商品価格の監視システム

from bs4 import BeautifulSoup
import requests

def get_product_price(url, price_selector):
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'}
    response = requests.get(url, headers=headers)
    soup = BeautifulSoup(response.content, 'html.parser')
    
    price_element = soup.select_one(price_selector)
    if price_element:
        price = price_element.text.strip()
        return price
    return None

# Amazon商品価格取得例(セレクターは実際のサイトに合わせて調整)
price = get_product_price("https://amazon.com/product/123", ".a-price-whole")
print(f"現在価格: {price}")

テーブルデータの抽出

from bs4 import BeautifulSoup
import requests
import pandas as pd

def scrape_table_data(url, table_selector):
    response = requests.get(url)
    soup = BeautifulSoup(response.content, 'html.parser')
    
    table = soup.select_one(table_selector)
    rows = table.find_all('tr')
    
    data = []
    for row in rows[1:]:  # ヘッダー行をスキップ
        cols = row.find_all(['td', 'th'])
        data.append([col.text.strip() for col in cols])
    
    return data

# 使用例
table_data = scrape_table_data("https://example.com/table", "table.data-table")
df = pd.DataFrame(table_data)
print(df.head())

BeautifulSoupの要素検索メソッド一覧

メソッド 使い方 戻り値
find() soup.find('tag', attrs={}) 最初の1つの要素
find_all() soup.find_all('tag') 該当する全ての要素のリスト
select() soup.select('css-selector') CSSセレクターで全要素
select_one() soup.select_one('css-selector') CSSセレクターで最初の1つ

属性による検索

from bs4 import BeautifulSoup

html = '<a href="https://example.com" target="_blank">リンク</a>'
soup = BeautifulSoup(html, 'html.parser')

# 属性で検索
link = soup.find('a', href="https://example.com")
external_links = soup.find_all('a', target="_blank")

# 属性値を取得
print(link['href'])  # https://example.com
print(link.get('target'))  # _blank

BeautifulSoupで使える便利なテクニック

1. 親要素・兄弟要素の取得

from bs4 import BeautifulSoup

html = """
<div class="parent">
<p>前の段落</p>
<p class="target">対象段落</p>
<p>次の段落</p>
</div>
"""

soup = BeautifulSoup(html, 'html.parser')
target = soup.find('p', class_='target')

print(target.parent.name)  # div(親要素)
print(target.previous_sibling.previous_sibling.text)  # 前の段落
print(target.next_sibling.next_sibling.text)  # 次の段落

2. テキストの清浄化

from bs4 import BeautifulSoup
import re

html = '<p>   不要な空白   \n\t改行文字\n   </p>'
soup = BeautifulSoup(html, 'html.parser')

# 基本的なテキスト取得
text = soup.p.text
clean_text = re.sub(r'\s+', ' ', text.strip())
print(clean_text)  # 不要な空白 改行文字

# get_text()メソッドでより詳細な制御
clean_text = soup.p.get_text(strip=True, separator=' ')
print(clean_text)

3. 複数条件での検索

from bs4 import BeautifulSoup

html = """
<div class="item active">アクティブアイテム</div>
<div class="item">通常アイテム</div>
<div class="item featured">特集アイテム</div>
"""

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

# 複数クラスを持つ要素
active_item = soup.find('div', class_=['item', 'active'])

# カスタム関数での検索
def has_multiple_classes(tag):
    return tag.has_attr('class') and len(tag['class']) > 1

multi_class_items = soup.find_all(has_multiple_classes)
for item in multi_class_items:
    print(item.text)

BeautifulSoupでよくあるエラーと対処法

1. AttributeError: ‘NoneType’ object has no attribute

原因: 要素が見つからない場合にNoneが返される

from bs4 import BeautifulSoup

soup = BeautifulSoup('<div></div>', 'html.parser')

# 危険なコード
# print(soup.find('p').text)  # AttributeError

# 安全なコード
p_tag = soup.find('p')
if p_tag:
    print(p_tag.text)
else:
    print("要素が見つかりません")

2. エンコーディングエラー

import requests
from bs4 import BeautifulSoup

response = requests.get(url)
response.encoding = 'utf-8'  # エンコーディングを明示的に指定
soup = BeautifulSoup(response.content, 'html.parser')

3. パーサーの選択

from bs4 import BeautifulSoup

# 推奨: lxml(高速・正確)
soup = BeautifulSoup(html, 'lxml')

# フォールバック: html.parser(標準ライブラリ)
soup = BeautifulSoup(html, 'html.parser')

BeautifulSoupのパフォーマンス最適化

1. 適切なパーサーの選択

import time
from bs4 import BeautifulSoup

# 大きなHTMLファイルの場合
large_html = open('large_file.html').read()

# lxmlが最も高速
start = time.time()
soup = BeautifulSoup(large_html, 'lxml')
print(f"lxml: {time.time() - start:.3f}秒")

2. 必要な部分だけを解析

from bs4 import BeautifulSoup, SoupStrainer

# 特定のタグのみを解析
only_links = SoupStrainer('a')
soup = BeautifulSoup(html, 'lxml', parse_only=only_links)

# クラス名で限定
only_content = SoupStrainer('div', class_='content')
soup = BeautifulSoup(html, 'lxml', parse_only=only_content)

BeautifulSoupと他のライブラリとの連携

requestsとの組み合わせ

import requests
from bs4 import BeautifulSoup
import time

def safe_request(url, max_retries=3):
    for i in range(max_retries):
        try:
            response = requests.get(url, timeout=10)
            response.raise_for_status()
            return response
        except requests.RequestException as e:
            if i == max_retries - 1:
                raise e
            time.sleep(2 ** i)  # エクスポネンシャルバックオフ

response = safe_request("https://example.com")
soup = BeautifulSoup(response.content, 'html.parser')

pandasとの連携

from bs4 import BeautifulSoup
import pandas as pd
import requests

def scrape_to_dataframe(url, table_selector):
    response = requests.get(url)
    soup = BeautifulSoup(response.content, 'html.parser')
    
    tables = pd.read_html(str(soup.select_one(table_selector)))
    return tables[0] if tables else None

# HTMLテーブルを直接DataFrameに変換
df = scrape_to_dataframe("https://example.com", "table.data")
print(df.head())

実用的なBeautifulSoupスクレイピング事例

1. RSS feedの解析

from bs4 import BeautifulSoup
import requests

def parse_rss_feed(rss_url):
    response = requests.get(rss_url)
    soup = BeautifulSoup(response.content, 'xml')
    
    items = soup.find_all('item')
    articles = []
    
    for item in items[:5]:
        article = {
            'title': item.title.text,
            'link': item.link.text,
            'description': BeautifulSoup(item.description.text, 'html.parser').text
        }
        articles.append(article)
    
    return articles

# 使用例
articles = parse_rss_feed("https://example.com/rss")
for article in articles:
    print(f"タイトル: {article['title']}")

2. 画像URLの一括取得

from bs4 import BeautifulSoup
import requests
from urllib.parse import urljoin

def get_all_images(url):
    response = requests.get(url)
    soup = BeautifulSoup(response.content, 'html.parser')
    
    images = soup.find_all('img')
    image_urls = []
    
    for img in images:
        src = img.get('src')
        if src:
            # 相対URLを絶対URLに変換
            absolute_url = urljoin(url, src)
            image_urls.append(absolute_url)
    
    return image_urls

# 使用例
images = get_all_images("https://example.com")
for img_url in images[:3]:
    print(img_url)

3. SNSの投稿データ収集

from bs4 import BeautifulSoup
import requests
import json

def scrape_social_posts(url, post_selector):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
    }
    
    response = requests.get(url, headers=headers)
    soup = BeautifulSoup(response.content, 'html.parser')
    
    posts = soup.select(post_selector)
    post_data = []
    
    for post in posts[:10]:
        data = {
            'text': post.get_text(strip=True),
            'timestamp': post.find('time')['datetime'] if post.find('time') else None,
            'likes': extract_number(post.select_one('.like-count'))
        }
        post_data.append(data)
    
    return post_data

def extract_number(element):
    if element:
        return int(''.join(filter(str.isdigit, element.text)))
    return 0

BeautifulSoupのベストプラクティス

1. エラーハンドリングの実装

from bs4 import BeautifulSoup
import requests
import logging

def robust_scraping(url, selector):
    try:
        response = requests.get(url, timeout=10)
        response.raise_for_status()
        
        soup = BeautifulSoup(response.content, 'html.parser')
        elements = soup.select(selector)
        
        if not elements:
            logging.warning(f"要素が見つかりません: {selector}")
            return []
        
        return [elem.text.strip() for elem in elements]
        
    except requests.RequestException as e:
        logging.error(f"リクエストエラー: {e}")
        return []
    except Exception as e:
        logging.error(f"予期しないエラー: {e}")
        return []

2. レート制限の実装

import time
from bs4 import BeautifulSoup
import requests

class RateLimitedScraper:
    def __init__(self, delay=1):
        self.delay = delay
        self.last_request = 0
    
    def scrape(self, url, selector):
        # レート制限
        elapsed = time.time() - self.last_request
        if elapsed < self.delay:
            time.sleep(self.delay - elapsed)
        
        response = requests.get(url)
        self.last_request = time.time()
        
        soup = BeautifulSoup(response.content, 'html.parser')
        return soup.select(selector)

# 使用例
scraper = RateLimitedScraper(delay=2)  # 2秒間隔
results = scraper.scrape("https://example.com", ".item")

まとめ:BeautifulSoupでWebスクレイピングをマスターしよう

Python BeautifulSoupは、Webスクレイピングにおいて必須のライブラリです。この記事で紹介した基本的な使い方から実践的なテクニックまでを活用すれば、効率的にWebデータを収集・分析できるようになります。

重要なポイント

  • 適切なパーサー(lxml推奨)を選択する
  • エラーハンドリングを必ず実装する
  • レート制限でサーバーに配慮する
  • robots.txtとサイト利用規約を確認する

まずは簡単なHTMLの解析から始めて、徐々に複雑なWebスクレイピングプロジェクトに挑戦してみてください。BeautifulSoupをマスターすれば、Web上の膨大な情報を自動的に収集・活用できるようになります。


この記事がお役に立ちましたら、ぜひシェアしてください。BeautifulSoupやWebスクレイピングに関するご質問がございましたら、お気軽にコメントでお知らせください。

■プロンプトだけでオリジナルアプリを開発・公開してみた!!

■AI時代の第一歩!「AI駆動開発コース」はじめました!

テックジム東京本校で先行開始。

■テックジム東京本校

「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。

<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。

<月1開催>放送作家による映像ディレクター養成講座

<オンライン無料>ゼロから始めるPython爆速講座