Webページから特定のデータを収集する「スクレイピング」の基本フローは、requests でHTMLを取得し、BeautifulSoup で構造解析(パース)を行い、必要なタグを特定してデータを抜き出すという手順になります。
ここでは、スクレイピングの練習用に公開されているサンドボックスサイト(Books to Scrape)を対象に、商品タイトルと詳細ページへのURLを一覧で取得するコードを作成します。
目次
実行可能なサンプルコード
このコードは、架空の書店サイトから「商品名」と「リンクURL」を抽出し、コンソールに出力します。 入れ子構造(article > h3 > a)になっているタグの階層を正しく辿る方法に注目してください。
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
def scrape_product_list():
# スクレイピング練習用サイト(書籍一覧)
target_url = "http://books.toscrape.com/"
print(f"Fetching: {target_url} ...")
try:
# 1. HTMLの取得
response = requests.get(target_url, timeout=10)
response.raise_for_status()
# 2. BeautifulSoupオブジェクトの生成
# パーサーには標準的で扱いやすい html.parser を使用(html5libでも可)
soup = BeautifulSoup(response.text, "html.parser")
# 3. 商品リストの特定
# サイトの構造に合わせて親要素や繰り返し要素を特定します
# ここでは <article class="product_pod"> が各商品のコンテナです
products = soup.find_all("article", class_="product_pod")
print(f"Found {len(products)} products.\n")
# 4. ループ処理で各商品の情報を抽出
for product in products:
# articleタグの中から、さらに h3 > a タグを探します
h3_tag = product.find("h3")
if h3_tag:
link_tag = h3_tag.find("a")
# aタグが見つかった場合、テキストとhref属性を取得
if link_tag:
title = link_tag.get("title") # ツールチップ用のtitle属性を取得(省略なしの正式名称)
href = link_tag.get("href") # 相対パスを取得
# 相対パスを絶対パスに変換(実用的な処理)
full_url = urljoin(target_url, href)
print(f"Title: {title}")
print(f"URL: {full_url}")
print("-" * 40)
except requests.RequestException as e:
print(f"通信エラーが発生しました: {e}")
except Exception as e:
print(f"予期せぬエラーが発生しました: {e}")
if __name__ == "__main__":
scrape_product_list()
解説:スクレイピングの重要ポイント
1. find と find_all の使い分け
soup.find_all(...): ページ内に複数存在する要素(例:商品リスト、ニュース記事一覧)をすべて取得し、リスト形式で返します。これをfor文で回して一つずつ処理します。tag.find(...): 特定した要素(親要素)の中から、さらに特定の子要素(例:その商品の中のタイトル)を1つだけ探します。
2. 属性値の取得 (.get)
リンクURLなどの属性情報は、タグのテキスト(.text)ではなく、HTMLタグの中に埋め込まれています。 <a href="catalogue/..." ...> のようなタグから href の値を取り出すには、link_tag.get("href") メソッドを使用します。
3. URLの結合 (urljoin)
取得したリンクが catalogue/page-1.html のような「相対パス」である場合、そのままではブラウザで開けません。urllib.parse.urljoin を使用して、ベースとなるURLと結合し、「絶対パス」に変換するのが一般的な処理パターンです。
