プロジェクト概要
前提条件
- Pythonプログラミングの基本的な知識(変数、関数、クラスの概念)
- VSCodeエディタの基本操作ができること
- ターミナル(コマンドライン)の基本的な使用経験
- Gitとバージョン管理の基礎知識
- HTMLの基本構造に関する理解
開発環境
- Python 3.7以上
- VSCode(Visual Studio Code)
- Git(バージョン管理システム)
- GitHubアカウント
- requests
- beautifulsoup4
プロジェクト内容
このプロジェクトでは、PythonのrequestsライブラリとBeautifulSoupを使用して、練習用Webサイトから商品情報を自動的に収集するスクレイピングシステムを構築します。初心者でも段階的に学習できるよう、基本的な環境設定から実用的なデータ保存機能まで、5つのステップに分けて実装していきます。
プロジェクトの核となるのは、HTTP通信を使用したWebページ取得技術です。requestsライブラリでWebページを取得し、BeautifulSoupでHTML解析を実行することで、商品のタイトル、価格、説明文を正確に抽出します。これにより、実際の業務で活用できる実用的なツールを作成できます。
データ抽出においては、BeautifulSoupの強力なHTML解析機能を使用して、練習用サイトから商品情報を取得します。単純なデータ収集にとどまらず、取得したデータの検証やCSVファイルへの保存機能も実装し、実用性の高いシステムを構築します。
プロジェクトの特徴として、エラーハンドリングを重視した設計を採用しています。ネットワークエラー、HTML解析エラー、ファイル保存エラーなど、様々な例外状況に対応できるよう、適切なtry-except文を配置し、ユーザーに分かりやすいエラーメッセージを提供します。
また、ユーザーフレンドリーな対話式インターフェースも実装し、複数のURLを順番に処理できる機能を提供します。これにより、単なるスクリプトではなく、実際に活用できるアプリケーションとして完成させます。
最終的に、完成したプロジェクトをGitHubにアップロードし、ポートフォリオとして活用できる形にします。適切なドキュメント(README.md)の作成や、.gitignoreファイルの設定など、実際の開発現場で必要とされる技術も学習できます。
実装内容
- HTTP通信用ヘッダーの設定とWebページ取得システム
- 仮想環境の構築と依存関係管理(requirements.txt)
- BeautifulSoupを使用したHTML解析とデータ抽出ロジック
- 商品情報の辞書構造での管理システム
- CSVファイル形式でのデータ保存機能
- エラーハンドリングと再試行機能の実装
- 対話式ユーザーインターフェースの開発
- GitHubでのバージョン管理とポートフォリオ公開
得られるスキル
- requestsライブラリを使用したHTTP通信技術
- BeautifulSoupを使用したHTML解析とWebスクレイピング
- オブジェクト指向プログラミング(クラス設計と実装)
- エラーハンドリング(try-except文の実践的な使用)
得られる経験
- Webスクレイピング技術の実践的な習得
- API連携とHTTP通信の基礎経験
- ファイル操作とディレクトリ管理の実装
- 対話式インターフェースの開発経験
- GitHubを使用したバージョン管理の実践的経験
得られる成果物
- 完全に動作するWebスクレイピングシステム
- GitHubでのポートフォリオとして活用可能なプロジェクト
- 完全なPythonソースコード
このプロジェクトから応用できること
- 他のECサイトの商品情報収集ツールの開発
- 価格比較システムの構築
- ニュース記事自動収集ツールの作成
- 求人情報収集システムの開発
- 不動産情報自動取得ツールの構築
Step1:開発環境の準備とプロジェクト構造の作成
このステップでは、このプロジェクトを始めるための開発環境を整備し、必要なファイル構造を作成していきます。プログラミングを始める前の準備段階として、とても重要な作業になります。
※Step1の内容がわからない際は、下記記事にGitHubとVSCodeの連携について詳細を記載しているためご参照ください。

GitHubリポジトリの作成
まず最初に、プロジェクト専用のGitHubリポジトリを作成しましょう。
- GitHubの公式サイトにアクセスし、自分のアカウントでログインします
- 画面右上の「+」アイコンをクリックし、ドロップダウンメニューから「New repository」を選択します
- 新しいリポジトリの作成ページで、以下の情報を入力します
リポジトリの設定
- Repository name 「web_data_collector」と入力
- Description 「requestsとBeautifulSoupを使用したWebデータ収集ツール」と入力
- Visibility 「Public」を選択(ポートフォリオとして公開するため)
- Initialize this repository with
- 「Add a README file」にチェックを入れる
- 「Add .gitignore」で「Python」を選択
- 「Choose a license」は「None」のままにする
- 「Create repository」ボタンをクリックしてリポジトリを作成します
プロジェクトフォルダの作成
次に、プロジェクトを管理するための親フォルダを作成しましょう。
Windows・macOS共通
- デスクトップや任意の場所に新しいフォルダを作成します
- フォルダ名は任意ですが、ここでは例として「PythonPortfolio」に設定します
この親フォルダが、今後のプロジェクト全体を管理するルートディレクトリとなります。複数のプロジェクトを整理して管理するために作成しておくと便利です。
VSCodeでプロジェクトを開く
作成したGitHubリポジトリをローカルにクローンして開きましょう。
- VSCodeを起動します
- 左側のアクティビティバーからソース管理アイコン(分岐のようなアイコン)をクリックします
- 「リポジトリの複製」ボタンをクリックします
- 「GitHubから複製」を選択します
- 先ほど作成した「web_data_collector」リポジトリを選択します
- リポジトリ宛先として先ほど作成した親フォルダを選択します
- 「クローンしたリポジトリを開きますか」というウィンドウが表示されたら「開く」をクリックします
VSCodeの左側にエクスプローラーパネルが表示され、現在のプロジェクトフォルダの中身が確認できるようになります。
仮想環境の作成とアクティベート
Python開発において仮想環境は非常に重要です。仮想環境とは、プロジェクトごとに独立したPython実行環境を作成する仕組みのことです。これにより、プロジェクト間でのライブラリの競合を防ぎ、クリーンな開発環境を維持できます。
詳しくは下記記事をご参照ください。
Windows環境での仮想環境作成
- VSCodeの上部メニューから「ターミナル」→「新しいターミナル」を選択
- 以下のコマンドで仮想環境を作成します
python -m venv myenv
- 仮想環境をアクティベートします
myenv\Scripts\activate
macOS環境での仮想環境作成
- VSCodeの上部メニューから「ターミナル」→「新しいターミナル」を選択
- 以下のコマンドで仮想環境を作成します
python3 -m venv myenv
- 仮想環境をアクティベートします
source myenv/bin/activate
重要なポイント
- 仮想環境名は「myenv」として作成
- ターミナルの行頭に「(myenv)」と表示されることを確認
- この表示があることで、仮想環境が正常にアクティベートされていることがわかります
プロジェクトファイル構造の作成
次に、今回のWebデータ収集プロジェクトに必要なフォルダとファイルを作成していきます。VSCodeのエクスプローラーパネルを使用してファイルを作成しましょう。
ソースコード用フォルダの作成
- VSCodeの左側エクスプローラーパネルで「新しいフォルダ」アイコン(フォルダの絵とプラスのマークがあるアイコン)をクリック
- フォルダ名を「src」として作成
この「src」フォルダはsource code(ソースコード)の略で、プログラムのメインファイルを格納するための専用フォルダです。プロジェクトの整理整頓において重要な役割を果たします。
収集データ保存用フォルダの作成
- 同じくエクスプローラーパネルで「新しいフォルダ」アイコンをクリック
- フォルダ名を「collected_data」として作成
「collected_data」フォルダは、Webから収集したデータを保管するためのフォルダです。今回のプロジェクトでは、Webサイトから抽出した情報がここに保存されます。
メインプログラムファイルの作成
- 先ほど作成した「src」フォルダをクリックして選択
- 「新しいファイル」アイコン(ファイルの絵とプラスのマークがあるアイコン)をクリック
- ファイル名を「web_scraper.py」として作成
この「web_scraper.py」ファイルが、今回のWebデータ収集機能を実装するメインプログラムとなります。.py拡張子はPythonスクリプトファイルであることを示しており、実行可能なプログラムコードを記述するために使用します。
依存関係管理ファイルの作成
- プロジェクトのルートフォルダ(web_data_collector)をクリックして選択
- 「新しいファイル」アイコンをクリック
- ファイル名を「requirements.txt」として作成
requirements.txtファイルは、Pythonプロジェクトで使用する外部ライブラリとそのバージョンを記録するための重要なファイルです。これにより、他の開発者や本番環境でも同じライブラリ環境を再現できます。
requirements.txtの内容設定
作成した「requirements.txt」ファイルをVSCodeで開き、以下の内容を記述してください。
requests==2.32.3
beautifulsoup4==4.13.4
今回のプロジェクトでは、requestsとbeautifulsoup4の2つのライブラリを使用します。
- requests HTTP通信を簡単に行うためのライブラリです。WebサイトやAPIに対してデータの送受信を行う際に使用します。Webページの取得を効率的に実行する際に重要な役割を果たします
- beautifulsoup4 HTML文書を解析し、必要な情報を抽出するためのライブラリです。Webスクレイピングにおいて、HTMLから特定の要素を取得する際に使用します。複雑なHTML構造からデータを正確に抽出できる便利なツールです
プロジェクト構造の確認
この時点で、VSCodeのエクスプローラーパネルには以下のような構造が表示されているはずです。
web_data_collector/
├── myenv/ # 仮想環境フォルダ
├── src/
│ └── web_scraper.py # メインプログラムファイル
├── collected_data/ # 収集データ保存フォルダ
├── requirements.txt # 依存関係管理ファイル
├── README.md # プロジェクト説明書(GitHub作成時に自動生成)
└── .gitignore # Git除外設定ファイル(GitHub作成時に自動生成)
この基本構造が、今回のWebデータ収集プロジェクトの基盤となります。GitHubで作成したリポジトリをクローンしたため、README.mdと.gitignoreファイルが最初から含まれています。
仮想環境が正常にアクティベートされていることを再度確認し(ターミナルに「(myenv)」が表示されている状態)、次のステップに進む準備を整えましょう。
ライブラリのインストール
仮想環境がアクティベートされている状態で、VSCodeのターミナルから以下のコマンドを実行します。
pip install -r requirements.txt
このコマンドにより、requirements.txtに記載されたrequestsとbeautifulsoup4ライブラリがインストールされます。インストール処理には数十秒程度かかる場合がありますので、しばらくお待ちください。
インストールが完了すると、ターミナルに「Successfully installed requests-2.32.3 beautifulsoup4-4.13.4」のようなメッセージが表示され、プロジェクトの環境準備が完了します。
Step2:HTTPリクエスト処理とWebページ取得機能の実装
このステップでは、練習用Webサイトからデータを取得するためのHTTPリクエスト処理と基本的なWebページ取得機能を実装します。requestsライブラリを使用して、スクレイピングの基礎を学べる安全で効率的なWeb通信システムを構築していきます。
WebScraperクラスの作成
まず、データ収集機能をまとめて管理するクラスを作成します。このクラスの中に、今後必要な機能をすべてdef文(関数)として実装していきます。
「src/web_scraper.py」ファイルを開き、以下のコードを記述してください。
# 必要なライブラリをインポート
import requests # HTTP通信を行うためのライブラリ
from bs4 import BeautifulSoup # HTML解析用のライブラリ
import os # ファイルやフォルダ操作用のライブラリ
class WebScraper:
def __init__(self, output_directory="collected_data"):
"""
WebScraperクラスの初期化
output_directory: 収集したデータを保存するフォルダ名
"""
# データ保存先ディレクトリの設定
self.output_folder = output_directory
# ディレクトリが存在しない場合は作成
os.makedirs(self.output_folder, exist_ok=True)
# HTTP設定の初期化を実行
self.setup_http_config()
# 初期化完了メッセージを表示
print(f"WebScraper初期化完了 - 保存先: {self.output_folder}")
initメソッドはクラスの初期化を行う特別な関数です。ここでデータの保存先ディレクトリを設定し、HTTP通信の設定を呼び出します。
HTTP通信設定機能
次に、クラス内にsetup_http_configメソッドを実装します。
def setup_http_config(self):
"""
HTTP通信用の設定を初期化
練習用ページ取得のためのヘッダー情報とタイムアウト設定を行う
"""
# HTTP通信用ヘッダー設定(ブラウザのふりをするための情報)
self.headers = {
# ブラウザの種類とバージョン情報を設定
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
# 受け取り可能なデータ形式を指定
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
# 言語設定(日本語を優先)
'Accept-Language': 'ja,en-US;q=0.7,en;q=0.3',
# データ圧縮形式の対応状況を指定
'Accept-Encoding': 'gzip, deflate, br',
# 接続を維持する設定
'Connection': 'keep-alive',
# セキュアな接続への自動アップグレード設定
'Upgrade-Insecure-Requests': '1'
}
# リクエストのタイムアウト時間を10秒に設定
self.timeout = 10
# 設定完了メッセージを表示
print("HTTP設定完了")
このメソッドはクラス内で定義されているため、selfキーワードを使用してクラスの属性にアクセスできます。
User-Agentについて
User-Agentは、Webブラウザがサーバーに対して自分の身元を伝えるための情報です。この設定により、プログラムが実際のブラウザのように動作してサーバーから練習用データを取得できます。
Webページ取得機能の実装
WebScraperクラス内に、指定されたURLから練習用Webページを取得するメソッドを追加します。
def fetch_webpage(self, url):
"""
指定されたURLから練習用Webページを取得
url: 取得したい練習ページのURL
"""
try:
# 処理開始メッセージを表示
print(f"練習用ページ取得開始: {url}")
# HTTPリクエストを送信してWebページを取得
response = requests.get(
url, # 取得するURL
headers=self.headers, # HTTPヘッダー情報
timeout=self.timeout # タイムアウト時間
)
# HTTPステータスコードの確認(200なら成功)
if response.status_code == 200:
# 成功メッセージとステータスコードを表示
print(f"✓ ページ取得成功 - ステータスコード: {response.status_code}")
# HTMLテキストを返す
return response.text
else:
# 失敗メッセージとステータスコードを表示
print(f"✗ ページ取得失敗 - ステータスコード: {response.status_code}")
return None
# タイムアウトエラーの処理
except requests.exceptions.Timeout:
print(f"✗ タイムアウトエラー: {url}")
return None
# 接続エラーの処理
except requests.exceptions.ConnectionError:
print(f"✗ 接続エラー: {url}")
return None
# その他のHTTPリクエストエラーの処理
except requests.exceptions.RequestException as error:
print(f"✗ リクエストエラー: {error}")
return None
# 予期しないエラーの処理
except Exception as error:
print(f"✗ 予期しないエラー: {error}")
return None
このメソッドでは、指定されたURLに対してHTTPリクエストを送信し、response.textでHTML形式の返事を受け取ります。response.status_codeでHTTPステータスコードを確認しています。
URL検証機能の実装
入力されたURLが正しい形式かを確認するメソッドをクラス内に追加します。
def validate_url(self, url):
"""
URLが正しい形式かを検証
url: 検証するURL文字列
"""
# URLの基本チェック(空でない、文字列である)
if not url or not isinstance(url, str):
print("✗ URLが入力されていません")
return False
# httpsまたはhttpで始まっているかチェック
if not (url.startswith('https://') or url.startswith('http://')):
print("✗ URLはhttps://またはhttp://で始まる必要があります")
return False
# 基本的なドメイン形式をチェック(ドットが含まれているか)
if '.' not in url:
print("✗ 有効なドメインが含まれていません")
return False
# 全ての検証をクリアした場合
print("✓ URLの形式が正しいです")
return True
isinstance()関数を使用して、URLが文字列型かどうかを確認し、基本的なURL形式をチェックしています。
接続テスト機能の実装
指定された練習用Webサイトに正常に接続できるかテストするメソッドをクラス内に追加します。
def test_connection(self, url):
"""
指定されたURLへの接続テスト
url: テストする練習用URL
"""
# テスト開始メッセージを表示
print(f"\n--- 接続テスト実行中 ---")
# URL形式の検証を実行
if not self.validate_url(url):
return False
# 練習用Webページ取得テストを実行
html_content = self.fetch_webpage(url)
# 取得が成功した場合
if html_content:
# 取得したHTMLの文字数を計算
content_length = len(html_content)
# HTMLサイズを表示(カンマ区切りで見やすく)
print(f"✓ HTML取得成功 - サイズ: {content_length:,} 文字")
# HTMLの最初の100文字を表示(デバッグ用)
# 改行文字を空白に置換して1行で表示
preview = html_content[:100].replace('\n', ' ').replace('\r', ' ')
print(f"HTMLプレビュー: {preview}...")
return True
else:
# 取得が失敗した場合
print("✗ 接続テスト失敗")
return False
このメソッドは、URL検証とWebページ取得の処理を順番に実行し、取得したHTMLの基本情報を表示します。
テスト実行機能の実装
クラスの動作をテストするための機能を追加します。
def main():
"""
WebScraperの基本動作テスト
クラスの初期化と接続テストを実行
"""
# テスト開始メッセージを表示
print("=== Webスクレイピング練習システム 基本テスト ===")
# WebScraperクラスのインスタンスを作成
scraper = WebScraper()
# テスト用のURL(スクレイピング練習用サイト)
test_url = "https://webscraper.io/test-sites/e-commerce/allinone"
# 接続テストを実行
connection_result = scraper.test_connection(test_url)
# 結果に応じてメッセージを表示
if connection_result:
print("\n✓ 練習用サイトへの接続が正常に動作しています")
else:
print("\n✗ 基本機能に問題があります")
print("ネットワーク接続やURL設定を確認してください")
# このファイルが直接実行された場合のみmain関数を呼び出し
if __name__ == "__main__":
main()
動作テスト実行
VSCodeのターミナルでプログラムを実行してテストします。
python src/web_scraper.py
出力結果
=== Webスクレイピング練習システム 基本テスト ===
WebScraper初期化完了 - 保存先: collected_data
HTTP設定完了
--- 接続テスト実行中 ---
✓ URLの形式が正しいです
練習用ページ取得開始: https://webscraper.io/test-sites/e-commerce/allinone
✓ ページ取得成功 - ステータスコード: 200
✓ HTML取得成功 - サイズ: 12,458 文字
HTMLプレビュー: <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-C...
✓ 練習用サイトへの接続が正常に動作しています
Step3:HTML解析とデータ抽出システムの構築
このステップでは、取得したHTMLから特定の情報を抽出するHTML解析機能とデータ抽出システムを実装します。BeautifulSoupを使用してHTML構造を解析し、練習用サイトから商品情報を正確に取得していきます。
HTML解析機能の実装
WebScraperクラス内に、取得したHTMLを解析するメソッドを追加します。
既存のコードに以下のメソッドを追加してください
def parse_html_content(self, html_content):
"""
HTMLコンテンツを解析してBeautifulSoupオブジェクトを作成
html_content: 解析するHTML文字列
"""
try:
# BeautifulSoupを使ってHTMLを解析
# 'html.parser'は標準的なHTMLパーサーを指定
soup = BeautifulSoup(html_content, 'html.parser')
# 解析完了メッセージを表示
print("✓ HTML解析完了")
return soup
# 解析エラーが発生した場合の処理
except Exception as error:
print(f"✗ HTML解析エラー: {error}")
return None
BeautifulSoupは、HTMLやXMLを解析するためのライブラリで、html.parserは標準的なHTMLパーサーを指定しています。
データ抽出機能の実装
練習用サイトから商品情報を抽出するメソッドをクラス内に追加します。
def extract_product_data(self, soup):
"""
BeautifulSoupオブジェクトから商品データを抽出
soup: 解析済みのBeautifulSoupオブジェクト
"""
try:
# 処理開始メッセージを表示
print("商品データ抽出開始...")
# 抽出したデータを格納するリストを初期化
products_list = []
# 商品情報を含むdivタグを全て取得
# class属性が'col-md-4 col-xl-4 col-lg-4'の要素を検索
product_elements = soup.find_all('div', class_='col-md-4 col-xl-4 col-lg-4')
# 発見された商品数を表示
print(f"発見された商品数: {len(product_elements)}")
# 各商品要素から情報を抽出
for product_element in product_elements:
# 商品タイトルの抽出(完全なタイトルを取得)
title_element = product_element.find('a', class_='title')
if title_element:
# title属性も確認して完全なタイトルを取得
product_title = title_element.get('title', '').strip()
# title属性が空の場合はテキスト内容を使用
if not product_title:
product_title = title_element.text.strip()
else:
# タイトル要素が見つからない場合
product_title = "タイトル不明"
# 商品価格の抽出
# class属性が'price float-end card-title pull-right'のh4タグを検索
price_element = product_element.find('h4', class_='price float-end card-title pull-right')
# 価格要素が見つかった場合はテキストを取得、見つからない場合はデフォルト値
product_price = price_element.text.strip() if price_element else "価格不明"
# 商品説明の抽出
# class属性が'description card-text'のpタグを検索
description_element = product_element.find('p', class_='description card-text')
# 説明要素が見つかった場合はテキストを取得、見つからない場合はデフォルト値
product_description = description_element.text.strip() if description_element else "説明なし"
# 抽出したデータを辞書形式で保存
product_info = {
'title': product_title,
'price': product_price,
'description': product_description
}
# 商品情報をリストに追加
products_list.append(product_info)
# 抽出完了メッセージと件数を表示
print(f"✓ データ抽出完了 - {len(products_list)}件の商品情報を取得")
return products_list
# データ抽出エラーが発生した場合の処理
except Exception as error:
print(f"✗ データ抽出エラー: {error}")
return []
find_all()メソッドでHTML内の全ての該当要素を取得し、find()メソッドで特定の要素を1つだけ取得します。text.strip()でテキスト内容を取得し、前後の空白を除去しています。
データ検証機能の実装
抽出されたデータが正しいかを確認するメソッドをクラス内に追加します。
def validate_extracted_data(self, products_data):
"""
抽出されたデータの検証
products_data: 抽出された商品データのリスト
"""
# データが空でないかチェック
if not products_data:
print("✗ 抽出されたデータがありません")
return False
# データの基本統計を計算
total_products = len(products_data) # 総商品数
# 有効なタイトルを持つ商品数をカウント
valid_titles = sum(1 for product in products_data if product['title'] != "タイトル不明")
# 有効な価格を持つ商品数をカウント
valid_prices = sum(1 for product in products_data if product['price'] != "価格不明")
# 検証結果を表示
print(f"データ検証結果:")
print(f" 総商品数: {total_products}")
print(f" 有効なタイトル: {valid_titles}")
print(f" 有効な価格: {valid_prices}")
# 検証成功の条件(有効なタイトルと価格が1件以上ある)
if valid_titles > 0 and valid_prices > 0:
print("✓ データ検証成功")
return True
else:
print("✗ データ検証失敗")
return False
このメソッドでは、抽出されたデータの品質をチェックし、有効なデータの割合を表示します。
データ表示機能の実装
抽出されたデータを見やすく表示するメソッドをクラス内に追加します。
def display_extracted_data(self, products_data, max_display=5):
"""
抽出されたデータを表示
products_data: 表示する商品データのリスト
max_display: 表示する最大件数
"""
# データが空でないかチェック
if not products_data:
print("表示可能なデータがありません")
return
# 表示開始メッセージ
print(f"\n=== 抽出されたデータ(最大{max_display}件表示) ===")
# 指定された件数まで表示(データ数と表示上限の小さい方を使用)
display_count = min(len(products_data), max_display)
# 指定件数分のデータを順番に表示
for i in range(display_count):
product = products_data[i] # i番目の商品データを取得
print(f"\n【商品 {i+1}】")
print(f"タイトル: {product['title']}")
print(f"価格: {product['price']}")
# 説明は100文字まで表示(長い場合は省略)
print(f"説明: {product['description'][:100]}...")
print("-" * 50) # 区切り線を表示
# 表示しきれなかったデータがある場合の注意書き
if len(products_data) > max_display:
remaining_count = len(products_data) - max_display
print(f"\n※ 他に{remaining_count}件のデータがあります")
min()関数を使用して表示件数を制限し、データの一部のみを見やすく表示します。
統合処理機能の実装
HTML取得からデータ抽出までの全工程をまとめたメソッドをクラス内に追加します。
def scrape_website_data(self, url):
"""
指定されたURLからデータを抽出する統合処理
url: スクレイピング対象のURL
"""
# 処理開始メッセージを表示
print(f"\n{'='*60}")
print(f"Webスクレイピング実行開始")
print(f"対象URL: {url}")
print(f"{'='*60}")
# Step1: Webページの取得
html_content = self.fetch_webpage(url)
if not html_content:
print("✗ Webページの取得に失敗しました")
return None
# Step2: HTML解析
soup = self.parse_html_content(html_content)
if not soup:
print("✗ HTML解析に失敗しました")
return None
# Step3: データ抽出
products_data = self.extract_product_data(soup)
if not products_data:
print("✗ データ抽出に失敗しました")
return None
# Step4: データ検証
if not self.validate_extracted_data(products_data):
print("✗ データ検証に失敗しました")
return None
# 全ての処理が正常に完了
print("✓ 全ての処理が正常に完了しました")
return products_data
このメソッドは、Webページ取得、HTML解析、データ抽出、データ検証の4つのステップを順番に実行し、各段階の結果を確認します。
テスト実行機能の更新
main関数を以下のように更新してください
def main():
"""
WebScraperのデータ抽出機能テスト
練習用サイトから商品データを抽出してテスト
"""
# テスト開始メッセージを表示
print("=== Webスクレイピング データ抽出テスト ===")
# WebScraperクラスのインスタンスを作成
scraper = WebScraper()
# 練習用サイトのURL
target_url = "https://webscraper.io/test-sites/e-commerce/allinone"
# データ抽出の実行
extracted_data = scraper.scrape_website_data(target_url)
# 結果に応じた処理
if extracted_data:
# 抽出されたデータを表示
scraper.display_extracted_data(extracted_data)
# 成功メッセージとデータ件数を表示
print(f"\n✓ テスト成功 - {len(extracted_data)}件のデータを抽出しました")
else:
# 失敗メッセージを表示
print(f"\n✗ テスト失敗 - データの抽出ができませんでした")
# 以前のテスト機能(現在は使用しない)
# connection_result = scraper.test_connection(test_url)
# if connection_result:
# print("\n✓ 練習用サイトへの接続が正常に動作しています")
# このファイルが直接実行された場合のみmain関数を呼び出し
if __name__ == "__main__":
main()
動作テスト実行
VSCodeのターミナルでプログラムを実行してテストします。
python src/web_scraper.py
出力結果
=== Webスクレイピング データ抽出テスト ===
HTTP設定完了
WebScraper初期化完了 - 保存先: collected_data
============================================================
Webスクレイピング実行開始
対象URL: https://webscraper.io/test-sites/e-commerce/allinone
============================================================
練習用ページ取得開始: https://webscraper.io/test-sites/e-commerce/allinone
✓ ページ取得成功 - ステータスコード: 200
✓ HTML解析完了
商品データ抽出開始...
発見された商品数: 3
✓ データ抽出完了 - 3件の商品情報を取得
データ検証結果:
総商品数: 3
有効なタイトル: 3
有効な価格: 3
✓ データ検証成功
✓ 全ての処理が正常に完了しました
=== 抽出されたデータ(最大5件表示) ===
【商品 1】
タイトル: Dell Latitude...
価格: $1144.4
説明: Dell Latitude 5580, 15.6" FHD, Core i5-7300U, 8GB, 256GB SSD, Windows 10 Pro...
--------------------------------------------------
【商品 2】
タイトル: Acer Iconia
価格: $96.99
説明: 7" screen, Android, 16GB...
--------------------------------------------------
【商品 3】
タイトル: Asus ASUSPRO B...
価格: $1381.13
説明: Asus ASUSPRO B9440UA-GV0279R Gray, 14" FHD, Core i7-7500U, 16GB, 512GB SSD, Windows 10 Pro, Eng kbd...
--------------------------------------------------
✓ テスト成功 - 3件のデータを抽出しました
Step4:データ保存機能とエラーハンドリングの実装
このステップでは、抽出したデータをCSVファイルに保存する機能とより詳細なエラーハンドリングを実装します。CSV形式でのデータ保存と、ユーザーが実際に活用できる実用的なシステムを構築していきます。
データ保存機能の実装
WebScraperクラス内に、抽出したデータをCSVファイルとして保存するメソッドを追加します。
既存のコードに以下のメソッドを追加してください
# ファイルの先頭に新しいimport文を追加
import csv # CSVファイル操作用のライブラリ
from datetime import datetime # 日時操作用のライブラリ
ファイルの先頭に上記のimport文を追加してください。
商品データ抽出機能の詳細化
extract_product_dataメソッドを以下のように更新してください
def extract_product_data(self, soup):
"""
BeautifulSoupオブジェクトから商品データを抽出
soup: 解析済みのBeautifulSoupオブジェクト
"""
try:
# 処理開始メッセージを表示
print("商品データ抽出開始...")
# 抽出したデータを格納するリストを初期化
products_list = []
# 商品情報を含むdivタグを全て取得
# class属性が'col-md-4 col-xl-4 col-lg-4'の要素を検索
product_elements = soup.find_all('div', class_='col-md-4 col-xl-4 col-lg-4')
# 発見された商品数を表示
print(f"発見された商品数: {len(product_elements)}")
# 各商品要素から情報を抽出(ループ処理)
for product_element in product_elements:
# 商品タイトルの抽出(完全なタイトルを取得)
title_element = product_element.find('a', class_='title')
if title_element:
# title属性も確認して完全なタイトルを取得
product_title = title_element.get('title', '').strip()
# title属性が空の場合はテキスト内容を使用
if not product_title:
product_title = title_element.text.strip()
else:
# タイトル要素が見つからない場合のデフォルト値
product_title = "タイトル不明"
# 商品価格の抽出
# class属性が'price float-end card-title pull-right'のh4タグを検索
price_element = product_element.find('h4', class_='price float-end card-title pull-right')
# 価格要素が見つかった場合はテキストを取得、見つからない場合はデフォルト値
product_price = price_element.text.strip() if price_element else "価格不明"
# 商品説明の抽出
# class属性が'description card-text'のpタグを検索
description_element = product_element.find('p', class_='description card-text')
# 説明要素が見つかった場合はテキストを取得、見つからない場合はデフォルト値
product_description = description_element.text.strip() if description_element else "説明なし"
# 抽出したデータを辞書形式で保存
product_info = {
'title': product_title,
'price': product_price,
'description': product_description
}
# 商品情報をリストに追加
products_list.append(product_info)
# 抽出完了メッセージと件数を表示
print(f"✓ データ抽出完了 - {len(products_list)}件の商品情報を取得")
return products_list
# データ抽出エラーが発生した場合の処理
except Exception as error:
print(f"✗ データ抽出エラー: {error}")
return []
title_element.get(‘title’)でHTML要素のtitle属性から完全なタイトルを取得し、それが空の場合はテキスト内容を使用するようにしています。
def save_data_to_file(self, products_data, filename=None):
"""
抽出されたデータをCSVファイルに保存
products_data: 保存する商品データのリスト
filename: 保存ファイル名(指定しない場合は自動生成)
"""
try:
# ファイル名が指定されていない場合は自動生成
if filename is None:
# 現在の日時を取得してファイル名に使用
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"scraped_data_{timestamp}.csv"
# 保存先のフルパスを作成
file_path = os.path.join(self.output_folder, filename)
# CSVファイルとして保存
# newline=''でCSVファイルの改行処理を適切に行う
# encoding='utf-8'で日本語対応
with open(file_path, 'w', newline='', encoding='utf-8') as csv_file:
# CSVライターを作成
writer = csv.writer(csv_file)
# ヘッダー行を書き込み
writer.writerow(['タイトル', '価格', '説明'])
# 各商品データを順番に書き込み
for product in products_data:
writer.writerow([
product['title'], # 商品タイトル
product['price'], # 商品価格
product['description'] # 商品説明
])
# 保存完了メッセージとファイルパス、件数を表示
print(f"✓ データ保存完了: {file_path}")
print(f" 保存件数: {len(products_data)}件")
return file_path
# ファイル入出力エラーの処理
except IOError as io_error:
print(f"✗ ファイル保存エラー: {io_error}")
return None
# その他の予期しないエラーの処理
except Exception as error:
print(f"✗ データ保存中の予期しないエラー: {error}")
return None
csv.writer()でCSVファイルに書き込むためのライターを作成し、writerow()でヘッダーとデータ行を順番に書き込みます。newline=”でCSVファイルの改行処理を適切に行います。
データ保存結果確認機能の実装
保存されたファイルの内容を確認するメソッドをクラス内に追加します。
def verify_saved_file(self, file_path):
"""
保存されたCSVファイルの内容を確認
file_path: 確認するファイルのパス
"""
try:
# ファイルの存在確認
if not os.path.exists(file_path):
print(f"✗ ファイルが見つかりません: {file_path}")
return False
# ファイルサイズを取得
file_size = os.path.getsize(file_path)
# ファイル情報を表示
print(f"保存ファイル確認:")
print(f" ファイルパス: {file_path}")
# ファイルサイズをカンマ区切りで見やすく表示
print(f" ファイルサイズ: {file_size:,} バイト")
# CSVファイルを読み込んで行数を確認
with open(file_path, 'r', encoding='utf-8') as csv_file:
# CSVリーダーを作成
reader = csv.reader(csv_file)
# 全ての行をリストに読み込み
rows = list(reader)
# ヘッダー行を除いたデータ行数を計算
data_rows = len(rows) - 1 if len(rows) > 0 else 0
# ファイル内容の詳細を表示
print(f" データ行数: {data_rows}行")
# ヘッダー行があれば表示
header_text = ', '.join(rows[0]) if len(rows) > 0 else 'なし'
print(f" ヘッダー: {header_text}")
# 確認完了メッセージを表示
print("✓ ファイル保存が正常に完了しています")
return True
# ファイル確認エラーの処理
except Exception as error:
print(f"✗ ファイル確認エラー: {error}")
return False
csv.reader()で保存されたCSVファイルを読み込み、list()で全行をリストに変換して行数を確認します。ヘッダー行を除いたデータ行数を計算して表示しています。
エラー復旧機能の実装
スクレイピング中にエラーが発生した場合の復旧処理を行うメソッドをクラス内に追加します。
def handle_scraping_errors(self, url, max_retries=3):
"""
スクレイピングエラーの処理と再試行機能
url: スクレイピング対象のURL
max_retries: 最大再試行回数
"""
# 指定回数まで再試行を実行
for attempt in range(max_retries):
try:
# データ抽出を実行
result = self.scrape_website_data(url)
# 成功した場合は結果を返す
if result:
return result
else:
print(f"✗ データ取得に失敗しました")
# エラーが発生した場合の処理
except Exception as error:
print(f"✗ エラーが発生しました: {error}")
# 最後の試行でない場合は待機
if attempt < max_retries - 1:
# 待機時間を段階的に増加(2秒、4秒、6秒)
wait_time = (attempt + 1) * 2
print(f" {wait_time}秒待機してから再試行します...")
# time.sleepで待機を実行
import time
time.sleep(wait_time)
# 全ての試行が失敗した場合
print(f"✗ {max_retries}回の試行すべてが失敗しました")
return None
for文を使用して指定された回数まで再試行を行い、time.sleep()で試行間隔を設けています。待機時間は試行回数に応じて段階的に増加させています。
データ表示機能の更新
display_extracted_dataメソッドを以下のように更新してください
def display_extracted_data(self, products_data, max_display=5):
"""
抽出されたデータを表示
products_data: 表示する商品データのリスト
max_display: 表示する最大件数
"""
# データが空でないかチェック
if not products_data:
print("表示可能なデータがありません")
return
# 表示開始メッセージ
print(f"\n=== 抽出されたデータ(最大{max_display}件表示) ===")
# 指定された件数まで表示(データ数と表示上限の小さい方を使用)
display_count = min(len(products_data), max_display)
# 指定件数分のデータを順番に表示
for i in range(display_count):
product = products_data[i] # i番目の商品データを取得
print(f"\n【商品 {i+1}】")
print(f"タイトル: {product['title']}")
print(f"価格: {product['price']}")
# 説明は100文字まで表示(長い場合は省略)
print(f"説明: {product['description'][:100]}...")
print("-" * 50) # 区切り線を表示
# 表示しきれなかったデータがある場合の注意書き
if len(products_data) > max_display:
remaining_count = len(products_data) - max_display
print(f"\n※ 他に{remaining_count}件のデータがあります")
min()関数を使用して表示件数を制限し、データの一部のみを見やすく表示します。タイトルは省略せずに完全に表示し、説明のみ100文字に制限しています。
ユーザーインターフェース機能の実装
ユーザーが操作しやすい対話式インターフェースをクラス内に追加します。
def run_interactive_scraping(self):
"""
対話式スクレイピングモード
ユーザーからの入力を受け付けてスクレイピングを実行
"""
# 対話モードの開始メッセージを表示
print("\n" + "="*60)
print("Webスクレイピング 対話モード")
print("="*60)
print("使い方:")
print("1. スクレイピング対象のURLを入力してください")
print("2. 'exit'と入力すると終了します")
print("3. 練習用URL: https://webscraper.io/test-sites/e-commerce/allinone")
print("-"*60)
print("※ 今後このコードを元に他のURLに合わせて改良してみてください")
# スクレイピング実行回数のカウンターを初期化
scraping_count = 0
# 無限ループで対話を継続
while True:
try:
# ユーザー入力を取得(前後の空白を除去)
user_input = input("\nスクレイピング対象URL >>> ").strip()
# 終了コマンドの確認
if user_input.lower() == 'exit':
print(f"\nスクレイピングを終了します")
print(f"総実行回数: {scraping_count}回")
break
# 空の入力をスキップ
if not user_input:
print("URLを入力してください")
continue
# エラー復旧機能付きスクレイピング実行
extracted_data = self.handle_scraping_errors(user_input)
# スクレイピングが成功した場合
if extracted_data:
# データ表示
self.display_extracted_data(extracted_data)
# データ保存
saved_file = self.save_data_to_file(extracted_data)
# 保存に成功した場合はファイル確認を実行
if saved_file:
self.verify_saved_file(saved_file)
# 成功回数をカウント
scraping_count += 1
else:
# スクレイピングが失敗した場合
print("スクレイピングに失敗しました")
# Ctrl+Cによる中断の処理
except KeyboardInterrupt:
print(f"\n\nプログラムが中断されました")
print(f"総実行回数: {scraping_count}回")
break
# その他のエラーの処理
except Exception as interface_error:
print(f"エラーが発生しました: {interface_error}")
input().strip()でユーザー入力を取得し、KeyboardInterruptでCtrl+Cによる中断を検知します。練習用URLを表示して、今後の活用方法についてもメッセージで案内しています。
テスト実行機能の更新
main関数を以下のように更新してください
def main():
"""
WebScraperの完全版テスト
対話式モードでユーザー操作を受け付け
"""
# テスト開始メッセージを表示
print("=== Webスクレイピング 完全版システム ===")
# WebScraperクラスのインスタンスを作成
scraper = WebScraper()
# 対話式スクレイピングモードを開始
scraper.run_interactive_scraping()
# 以前のテスト機能(現在は使用しない)
# target_url = "https://webscraper.io/test-sites/e-commerce/allinone"
# extracted_data = scraper.scrape_website_data(target_url)
# if extracted_data:
# scraper.display_extracted_data(extracted_data)
# print(f"\n✓ テスト成功 - {len(extracted_data)}件のデータを抽出しました")
# このファイルが直接実行された場合のみmain関数を呼び出し
if __name__ == "__main__":
main()
動作テスト実行
VSCodeのターミナルでプログラムを実行してテストします。
python src/web_scraper.py
出力結果
=== Webスクレイピング 完全版システム ===
HTTP設定完了
WebScraper初期化完了 - 保存先: collected_data
============================================================
Webスクレイピング 対話モード
============================================================
使い方:
1. スクレイピング対象のURLを入力してください
2. 'exit'と入力すると終了します
3. 練習用URL: https://webscraper.io/test-sites/e-commerce/allinone
------------------------------------------------------------
※ 今後このコードを元に他のURLに合わせて改良してみてください
スクレイピング対象URL >>> https://webscraper.io/test-sites/e-commerce/allinone
============================================================
Webスクレイピング実行開始
対象URL: https://webscraper.io/test-sites/e-commerce/allinone
============================================================
練習用ページ取得開始: https://webscraper.io/test-sites/e-commerce/allinone
✓ ページ取得成功 - ステータスコード: 200
✓ HTML解析完了
商品データ抽出開始...
発見された商品数: 3
✓ データ抽出完了 - 3件の商品情報を取得
データ検証結果:
総商品数: 3
有効なタイトル: 3
有効な価格: 3
✓ データ検証成功
✓ 全ての処理が正常に完了しました
=== 抽出されたデータ(最大5件表示) ===
【商品 1】
タイトル: Dell Latitude 5580
価格: $1144.4
説明: Dell Latitude 5580, 15.6" FHD, Core i5-7300U, 8GB, 256GB SSD, Windows 10 Pro...
--------------------------------------------------
【商品 2】
タイトル: Acer Iconia
価格: $96.99
説明: 7" screen, Android, 16GB...
--------------------------------------------------
【商品 3】
タイトル: Asus ASUSPRO B9440UA
価格: $1381.13
説明: Asus ASUSPRO B9440UA-GV0279R Gray, 14" FHD, Core i7-7500U, 16GB, 512GB SSD, Windows 10 Pro, Eng kbd...
--------------------------------------------------
✓ データ保存完了: collected_data/scraped_data_20250608_143025.csv
保存件数: 3件
保存ファイル確認:
ファイルパス: collected_data/scraped_data_20250608_143025.csv
ファイルサイズ: 487 バイト
データ行数: 3行
ヘッダー: タイトル, 価格, 説明
✓ ファイル保存が正常に完了しています
スクレイピング対象URL >>> exit
スクレイピングを終了します
総実行回数: 1回
Step5:プロジェクトをGitHubにアップロード
このステップでは、完成したWebスクレイピングプロジェクトをGitHubにアップロードし、ポートフォリオとして活用できる形にします。最終的なファイル整理とコードの公開を行っていきます。
.gitignoreファイルの更新
既存の.gitignoreファイルに、プロジェクト固有の除外設定を追加します。
VSCodeで「.gitignore」ファイルを開き、以下の内容を末尾に追加してください。
# Virtual environment
myenv/
# Collected data files
collected_data/
*.csv
# Cache files
__pycache__/
*.pyc
*.pyo
これらを追加する理由について説明します。
- myenv/ 仮想環境フォルダはプロジェクト固有のため、リポジトリに含める必要がありません
- collected_data/ プログラム実行時に生成される収集データフォルダを除外
- *.csv スクレイピングで生成されるCSVファイルを除外
- pycache/ Pythonの実行時キャッシュフォルダを除外
- *.pyc, *.pyo Pythonコンパイル済みファイルを除外
README.mdファイルの更新
リポジトリ作成時に生成されたREADME.mdファイルの内容を、プロジェクトの詳細情報に更新します。
VSCodeで「README.md」ファイルを開き、内容を以下のように全て置き換えてください。
# Webスクレイピングデータ収集システム
## プロジェクト内容
requestsとBeautifulSoupを使用したWebスクレイピングツールです。練習用サイトから商品情報を自動的に収集し、CSVファイルに保存する機能を実装しています。Pythonによる HTTP通信、HTML解析、データ抽出技術を学習することを目的として開発しました。
## プロジェクト構成
```
web_data_collector/
├── src/
│ └── web_scraper.py # メインプログラム
├── collected_data/ # 収集データ保存フォルダ
├── requirements.txt # 依存関係管理
├── README.md # プロジェクト説明書
└── .gitignore # Git除外ファイル設定
```
## 必要要件/開発環境
- **Python 3.7以上**
- **VSCode** (開発環境)
- **Git** (バージョン管理)
- **インターネット接続** (Webスクレイピング用)
### 使用ライブラリ
- **requests** HTTP通信とWebページ取得処理
- **beautifulsoup4** HTML解析とデータ抽出処理
- **csv** CSVファイル形式での保存処理
- **os** ファイルシステム操作
## 機能
- **URL検証** 入力されたURLの形式確認と妥当性チェック
- **Webページ取得** HTTP通信によるWebページの自動取得
- **HTML解析** BeautifulSoupを使用したHTML構造の解析
- **データ抽出** 商品タイトル、価格、説明の自動抽出
- **CSV保存** 抽出データのCSVファイル形式での保存
- **エラーハンドリング** 通信エラーや解析エラーの適切な処理
- **再試行機能** 失敗時の自動再試行機能
- **対話式インターフェース** ユーザーフレンドリーなコマンドライン操作
## 実行方法
### 1. リポジトリのクローン
```bash
git clone https://github.com/yourusername/web_data_collector.git
cd web_data_collector
```
### 2. 仮想環境の作成・アクティベート
**Windows**
```bash
python -m venv myenv
myenv\Scripts\activate
```
**macOS**
```bash
python3 -m venv myenv
source myenv/bin/activate
```
### 3. 依存関係のインストール
```bash
pip install -r requirements.txt
```
### 4. プログラムの実行
```bash
python src/web_scraper.py
```
実行後、対話式インターフェースが起動し、URLを入力するとcollected_dataフォルダに収集したデータがCSVファイルとして保存されます。
## 使用方法
1. プログラムを実行すると対話式モードが開始されます
2. スクレイピング対象のURLを入力してください
3. 練習用URL: https://webscraper.io/test-sites/e-commerce/allinone
4. 'exit'と入力するとプログラムが終了します
## データ形式について
* **対象URL** 練習用スクレイピングサイト
* **出力データ** CSV形式の商品情報ファイル
* **保存場所** collected_dataフォルダ内
## 注意事項
- このツールは教育目的で作成されています
- 練習用サイト以外をスクレイピングする際は利用規約を確認してください
- 今後このコードを元に他のURLに合わせて改良してみてください
## 開発者
YuYu
プロジェクトのコミット・プッシュ
プロジェクトの全ての変更をGitHubに反映させましょう。
変更のステージングとコミット
- VSCodeの左側のアクティビティバーからソース管理アイコンをクリックします
- 変更内容セクションで、すべての変更ファイルを確認します
- 各ファイルの横にある「+」アイコンをクリックしてステージングします
- コミットメッセージ入力欄に「Add web scraping data collection system」と入力します
- 「コミット」ボタンをクリックします
GitHubへのプッシュ
- コミット完了後、「変更の同期」または「プッシュ」ボタンをクリックします
- 初回の場合、GitHub認証が求められる場合があります
- 認証完了後、ローカルの変更がGitHubリポジトリに反映されます
GitHubでの確認
プロジェクトが正常にアップロードされたか確認しましょう。
- ブラウザでGitHubリポジトリページを開きます
- 以下のファイルが正しくアップロードされていることを確認します
- src/web_scraper.py (メインプログラムファイル)
- requirements.txt (依存関係管理ファイル)
- README.md (更新されたプロジェクト説明書)
- .gitignore (更新された除外設定ファイル)
- README.mdが適切に表示され、プロジェクトの説明が読みやすく表示されていることを確認します
- ファイル一覧にmyenv/フォルダやcollected_data/フォルダが含まれていないことを確認します(.gitignoreで除外されているため)
これで本格的なWebスクレイピングシステムが完成し、GitHubでのポートフォリオ公開も完了しました。作成したプロジェクトは、就職活動や案件獲得時の実績として活用できる実用的なシステムとなっています。
まとめ
このプロジェクトを通じて、Pythonを使用したWebスクレイピングの基礎から実践的な応用まで幅広く学習することができました。
得られたスキル
- requestsライブラリ – HTTP通信とWebページ取得の基本操作
- BeautifulSoup – HTML解析とWebスクレイピング技術
- オブジェクト指向プログラミング – クラス設計と実装手法
- エラーハンドリング – try-except文を使用した例外処理
得られた経験
- Webスクレイピング技術の実践的な習得
- API連携とHTTP通信の基礎経験
- ファイル操作とディレクトリ管理の実装
- 対話式インターフェースの開発経験
- GitHubを使用したバージョン管理の実践的経験
得られた成果物
- 完全に動作するWebスクレイピングシステム
- GitHubでのポートフォリオとして活用可能なプロジェクト
- 完全なPythonソースコード
次に学ぶべきこと
- pandasを使用したデータ分析機能の追加
- CSSセレクタの活用による要素取得方法の拡張
- 異なるWebサイト構造への対応技術の学習
- データベースへの保存機能の実装
- 定期実行機能による自動化の実装
このプロジェクトから応用できること
- 他のECサイトの商品情報収集ツールの開発
- 価格比較システムの構築
- ニュース記事自動収集ツールの作成
- 求人情報収集システムの開発
- 不動産情報自動取得ツールの構築
- データ収集代行サービスの提供
このWebスクレイピング技術を基盤として、様々な分野でのデータ収集ニーズに対応できるサービスを開発することが可能です。特に、定期的な情報収集や価格監視が必要な業務では、高い価値を提供できる技術として活用できます。
本コンテンツへの意見や質問