一覧へ

ウェブクローリングの基礎 — BeautifulSoup

PythonのrequestsとBeautifulSoupを使って、ウェブページから必要なデータを抽出する方法を学びます。

中級
|
10
|
検証済み (2026-07)
ウェブクローリングBeautifulSouprequestsHTML解析スクレイピング
進捗0/17 (0%)

Webクローリングの基礎 — BeautifulSoup

このトピックを終えると

requestsを使ってWebページを取得し、BeautifulSoupを使って必要なデータを抽出する基本的な流れを実装できるようになります。


クローリングとは

Webクローリングとは、プログラムがWebページにアクセスしてデータを自動的に収集することです。スクレイピングとも呼ばれます。

ブラウザが行うことをコードで実現します。

  1. Webサーバーにリクエストを送信します。
  2. HTMLを取得します。
  3. HTMLから必要なデータを抽出します。

1段階 — HTMLの取得 (requests)

python
import requests
url = "https://example.com"
response = requests.get(url)
print(response.status_code) # 200 = 正常
print(response.text[:200]) # HTMLテキストの最初の200文字

requests.get(url)はブラウザのようにサーバーにリクエストを送信し、サーバーから送信されたHTMLをresponse.textで取得します。

python
# ステータスコードの確認
if response.status_code == 200:
html = response.text
elif response.status_code == 404:
print("ページが見つかりません")
elif response.status_code == 403:
print("アクセスが拒否されました")

2段階 — HTMLの解析 (BeautifulSoup)

python
from bs4 import BeautifulSoup
html = """
<html>
<body>
<h1 class="title">ニュースの見出し</h1>
<div class="content">
<p>最初の段落です。</p>
<p>2番目の段落です。</p>
</div>
<ul id="tags">
<li>Python</li>
<li>データ</li>
<li>クローリング</li>
</ul>
</body>
</html>
"""
soup = BeautifulSoup(html, "html.parser")

BeautifulSoupはHTML文字列を解析して、ツリー構造のオブジェクトを作成します。このオブジェクトからタグ、クラス、IDなどで必要な部分を見つけることができます。


3段階 — データの抽出

タグで検索

python
# 最初のh1タグ
title = soup.find("h1")
print(title.text) # "ニュースの見出し"
print(title["class"]) # ["title"]
# すべてのpタグ
paragraphs = soup.find_all("p")
for p in paragraphs:
print(p.text)
# "最初の段落です。"
# "2番目の段落です。"

CSSセレクターで検索

python
# select — CSSセレクターを使用 (querySelectorAllと同じ)
items = soup.select("ul#tags li")
for item in items:
print(item.text)
# "Python"
# "データ"
# "クローリング"
# クラスで選択
content = soup.select_one("div.content")
print(content.text.strip())

find/find_allよりも、select/select_oneの方がCSSに慣れている人にとっては直感的です。


実践的な例 — テーブルデータの抽出

python
table_html = """
<table>
<tr><th>名前</th><th>スコア</th></tr>
<tr><td>철수</td><td>85</td></tr>
<tr><td>영희</td><td>92</td></tr>
<tr><td>민수</td><td>78</td></tr>
</table>
"""
soup = BeautifulSoup(table_html, "html.parser")
rows = soup.select("tr")
data = []
for row in rows[1:]: # ヘッダーを除く
cols = row.find_all("td")
data.append({
"名前": cols[0].text,
"スコア": int(cols[1].text)
})
print(data)
# [{'名前': '철수', 'スコア': 85}, {'名前': '영희', 'スコア': 92}, {'名前': '민수', 'スコア': 78}]
python
# pandas DataFrameに直接変換
import pandas as pd
df = pd.DataFrame(data)
print(df)

注意点

リクエスト間隔

python
import time
urls = ["https://example.com/page/1", "https://example.com/page/2"]
for url in urls:
response = requests.get(url)
time.sleep(1) # 1秒待機 — サーバーに負担をかけないようにする

連続して高速にリクエストすると、サーバーに負担をかけたり、IPがブロックされたりする可能性があります。

User-Agentの設定

python
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/91.0"
}
response = requests.get(url, headers=headers)

一部のサーバーは、ボットをブロックするためにUser-Agentを確認します。

robots.txt

text
https://example.com/robots.txt

このファイルには、クローリングが許可されているパスと禁止されているパスが記載されています。サイトのクローリングポリシーを最初に確認することは、礼儀であり、法的安全策です。


クローリングの限界

BeautifulSoupは静的なHTMLのみを処理できます。JavaScriptで動的にロードされるコンテンツ(SPA、無限スクロールなど)はHTMLに含まれないため、抽出できません。

状況ツール
静的なHTMLrequests + BeautifulSoup
JavaScriptによる動的ロードSelenium, Playwright
APIを提供requestsでAPIを直接呼び出す(最も効率的)

APIがある場合は、クローリングよりもAPIを優先的に使用します。構造化されたデータを正確に取得でき、サーバーへの負担も軽減されます。


基本的な流れの要約

text
1. requests.get(url) → HTMLテキスト
2. BeautifulSoup(html) → 解析されたツリー
3. soup.select("CSSセレクター") → 必要な要素
4. element.text / element["attr"] → データ抽出

エラー処理

実際のクローリングでは、さまざまなエラーが発生します。

python
import requests
from bs4 import BeautifulSoup
def safe_fetch(url, retries=3):
for attempt in range(retries):
try:
response = requests.get(url, timeout=10)
response.raise_for_status()
return response.text
except requests.exceptions.Timeout:
print(f"タイムアウト ({attempt + 1}/{retries})")
except requests.exceptions.HTTPError as e:
print(f"HTTPエラー: {e}")
return None
except requests.exceptions.ConnectionError:
print(f"接続失敗 ({attempt + 1}/{retries})")
return None

timeoutを設定しないと、応答のないサーバーでプログラムが無限に待機します。raise_for_status()は、4xx/5xxレスポンスで例外を発生させます。


複数のページをクローリング

python
import time
base_url = "https://example.com/articles?page="
all_titles = []
for page in range(1, 11):
html = safe_fetch(f"{base_url}{page}")
if html is None:
continue
soup = BeautifulSoup(html, "html.parser")
titles = soup.select("h2.article-title")
all_titles.extend([t.text.strip() for t in titles])
print(f"ページ {page}: {len(titles)}件 収集")
time.sleep(1)
print(f"合計 {len(all_titles)}件 収集完了")

クローリング結果の保存

python
import json
import csv
# JSONで保存
with open("articles.json", "w", encoding="utf-8") as f:
json.dump(all_titles, f, ensure_ascii=False, indent=2)
# CSVで保存
with open("articles.csv", "w", encoding="utf-8", newline="") as f:
writer = csv.writer(f)
writer.writerow(["番号", "タイトル"])
for i, title in enumerate(all_titles, 1):
writer.writerow([i, title])

収集したデータは、JSONまたはCSVで保存して、pandasで直接分析できるようにします。


リンクの抽出 — href属性

python
# ページ内のすべてのリンクを抽出
links = soup.select("a[href]")
for link in links:
url = link["href"]
text = link.text.strip()
print(f"{text}: {url}")
# 特定のパターンのリンクのみ
article_links = [
a["href"] for a in soup.select("a[href]")
if "/article/" in a.get("href", "")
]

クローリングは、「データを取得する技術」の第一歩です。データ分析、機械学習、モニタリングなど、あらゆる場所でデータ収集が出発点となります。

💬 質問・コメント

0件のコメント

ログインせずに投稿できます。ゲスト投稿は投稿者自身で編集・削除できません。

0/2000

読み込み中...