スクレイピングでAIファインチューニングデータを生成:高品質データ収集から実践手順まで徹底解説
AIモデルの性能は、その学習データの質と量に大きく依存します。特に、特定のドメインやタスクに特化したAIモデルを構築する際、既存の公開データセットでは求める要件を満たせないことが少なくありません。本記事では、ウェブスクレイピングを活用してAIファインチューニング用の高品質なデータセットを効率的に生成する実践的な手順を、現場のリアルな知見を交えながら徹底解説します。
課題・背景
AI開発において「データは新しい石油」とまで言われるように、モデルの精度向上には適切なデータの準備が不可欠です。特に大規模言語モデル(LLM)のような汎用モデルを特定の業務や業界に最適化(ファインチューニング)する場合、そのドメインに特化した高品質なデータがなければ、期待する性能を引き出すことはできません。
しかし、この独自データの収集にはいくつかの課題が伴います。
- 既存データセットの限界: 公開されているデータセットは汎用的なものが多く、特定のニッチなドメイン(例:日本の特定の法律分野、社内独自の技術ドキュメント)には対応しきれない。
- データ作成のコスト: ゼロから手作業で大量のデータを生成・アノテーションするのは膨大な時間とコストがかかり、スケーラビリティに欠ける。
- データの鮮度と多様性: ビジネス環境の変化に伴い情報は常に更新されるため、一度作成したデータセットがすぐに陳腐化する可能性がある。また、単一のソースからのデータではバイアスが生じやすい。
これらの課題に対し、ウェブスクレイピングはインターネット上に存在する膨大な情報を効率的に収集し、AIファインチューニングに最適な形に加工する強力な手段となります。しかし、単にデータを集めるだけでなく、そのデータの品質、倫理的・法的側面、そしてAIモデルが学習しやすい形への変換プロセスまでを理解し実践することが、独学エンジニアや実務初学者にとっての大きな壁となるでしょう。
実践・解決策
ここでは、ウェブスクレイピングを通じてAIファインチューニングデータを生成する具体的なステップとコード例を解説します。
ステップ1: ターゲット選定と戦略立案
まず、どのようなデータが必要で、どこから収集するかを明確にします。
- 目的の明確化: AIモデルで何を達成したいか(例: 特定分野のQ&A、要約、翻訳)。
- 情報源の特定: 目的のデータが豊富に存在するWebサイトを特定します。複数のサイトから収集することで、データの多様性を確保できます。
- サイト構造の分析: 対象サイトのHTML構造、URLパターン、動的なコンテンツの有無などをブラウザの開発者ツールで詳細に分析します。
-
robots.txtの確認: サイトのルートディレクトリにあるrobots.txtファイルを確認し、スクレイピングが許可されている範囲を把握します。これはウェブスクレイピングにおける最低限の法的・倫理的配慮であり、無視するとトラブルの原因となる可能性があります。
ステップ2: スクレイピング環境の構築
Pythonはウェブスクレイピングのデファクトスタンダードです。主要ライブラリは以下の通りです。
-
requests: HTTPリクエストを送信し、Webページのコンテンツを取得します。 -
BeautifulSoup4(bs4): HTMLやXMLドキュメントを解析し、必要な情報を効率的に抽出します。 -
selenium/Playwright: JavaScriptによって動的にコンテンツが生成されるWebサイトの場合に利用します。ヘッドレスブラウザを操作することで、人間がブラウザで閲覧するのと同じようにコンテンツを取得できます。今回はシンプルにrequestsとBeautifulSoupに焦点を当てます。
必要なライブラリをインストールします。
pip install requests beautifulsoup4
ステップ3: データ抽出とファインチューニング用データ(JSONL)の生成
ここでは、requestsとBeautifulSoupを用いてWebページからテキストデータを抽出し、不要な空白や改行をクレンジングしたうえで、LLMのファインチューニングで標準的に使われるJSONL(JSON Lines)形式のデータセットとして保存する実践的な実装例を紹介します。
import json
import re
import time
import requests
from bs4 import BeautifulSoup
def clean_text(text: str) -> str:
"""抽出したテキストから余分な空白や改行を除去して整形する"""
text = re.sub(r"\s+", " ", text)
return text.strip()
def scrape_and_create_dataset(urls: list[str], output_path: str) -> None:
"""指定URL群からコンテンツを抽出し、ファインチューニング用JSONLを生成する"""
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"
}
dataset = []
for url in urls:
print(f"スクレイピング実行中: {url}")
try:
# タイムアウトを設定してHTTP GETリクエストを送信
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
# BeautifulSoupでHTMLを解析
soup = BeautifulSoup(response.text, "html.parser")
# ナビゲーションやスクリプト等のノイズ要素を削除
for tag in soup(["script", "style", "nav", "footer", "header"]):
tag.decompose()
# タイトルと本文テキストの抽出・クレンジング
title = clean_text(soup.title.string) if soup.title and soup.title.string else "タイトルなし"
paragraphs = [clean_text(p.get_text()) for p in soup.find_all("p") if len(clean_text(p.get_text())) > 30]
body_text = "\n".join(paragraphs)
if body_text:
# ファインチューニング(Instruction Tuning)用のフォーマットに整形
record = {
"instruction": f"次のトピック「{title}」について、専門的な観点から分かりやすく解説してください。",
"input": "",
"output": body_text,
"source_url": url
}
dataset.append(record)
except requests.exceptions.Timeout:
print(f"エラー: リクエストがタイムアウトしました ({url})")
except requests.exceptions.RequestException as e:
print(f"エラー: HTTPリクエスト中に問題が発生しました ({url}): {e}")
except Exception as e:
print(f"エラー: 予期せぬエラーが発生しました ({url}): {e}")
# サーバー負荷軽減のため必ずアクセス間隔を空ける
time.sleep(2)
# JSONL形式でファイルに書き出し
with open(output_path, "w", encoding="utf-8") as f:
for item in dataset:
f.write(json.dumps(item, ensure_ascii=False) + "\n")
print(f"\n完了: {len(dataset)} 件のデータを {output_path} に保存しました。")
if __name__ == "__main__":
# テスト用のURLリスト(実運用時は許可された対象サイトのURLを指定)
target_urls = [
"[https://www.example.com](https://www.example.com)"
]
scrape_and_create_dataset(target_urls, "finetuning_dataset.jsonl")
このように、HTMLから本文以外のノイズ(<nav>や<script>など)を取り除き、モデルが学習しやすいプロンプトと応答のペア(instruction / output)へ構造化することで、実用的なデータセットを効率よく構築できます。
注意点・ハマりどころ
Webスクレイピングは強力なツールですが、その利用には技術的な知識だけでなく、倫理的、法的な配慮が不可欠です。独学で進める方も、現場で初めて担当する方も、以下の点に特に注意してください。
1. サイトの利用規約とrobots.txtの確認
最も重要かつ最初に確認すべき点です。
- 利用規約: スクレイピング対象サイトの利用規約には、データ収集に関する項目が含まれていることがあります。規約に反する行為は、法的な問題に発展する可能性があります。
-
robots.txt: Webサイトのルートディレクトリに配置されているrobots.txtファイルは、検索エンジンクローラーなどのロボットに対して、どのページへのアクセスを許可し、どのページを拒否するかを指示する標準的な仕組みです。robots.txtで拒否されているパスにスクレイピングを行うのは、原則として避けるべきです。-
現場の工夫:
robots.txtはあくまで「リクエスト」ですが、開発者の意図を尊重し、不要なトラブルを避けるために必ず従いましょう。特に企業のWebサイトをスクレイピングする際は、法務部門や広報部門との連携が重要になることもあります。
-
現場の工夫:
2. サーバー負荷への配慮とアクセス間隔
スクレイピングは、短時間に大量のリクエストをWebサーバーに送信する行為です。
- DDoS攻撃とみなされる可能性: 無計画な大量アクセスは、Webサーバーに過度な負荷をかけ、サイトのダウンやサービス品質の低下を招く恐れがあります。これは、悪意のあるDDoS攻撃と区別がつきにくく、法的な責任を問われる可能性もあります。
-
解決策:
-
time.sleep(): リクエスト間に適切な待機時間を設ける(例:time.sleep(2)で2秒待つ)。 - キャッシュの利用: 一度取得したデータは可能な限りキャッシュし、同じデータを何度もリクエストしないようにします。
-
非同期処理: 高度なテクニックとして、
asyncioとaiohttpを組み合わせることで、サーバーに負荷をかけすぎない範囲で効率的にリクエストを並行処理できますが、同時接続数の制限(セマフォなど)を必ず設ける必要があります。 - インフラ/NW視点: サイトのサーバーリソースは有限です。あなたのスクレイピングが、一般ユーザーのサービス利用に影響を与えることがないよう、十分な配慮が必要です。
-
3. IPアドレスのブロックと回避策
多くのWebサイトは、短時間に同じIPアドレスからの異常なアクセスを検知すると、そのIPアドレスからのアクセスを一時的または永続的にブロックする対策を講じています。
-
回避策:
- プロキシサーバーの利用: 複数のIPアドレスを持つプロキシサーバーを経由してリクエストを送信し、IPアドレスを分散させます。有料のプロキシサービスは、高速かつ安定したIPローテーション機能を提供します。
- VPNの利用: VPNサービスを利用して、IPアドレスを切り替えながら検証を行います。
- ローカル環境での試行錯誤: 自宅のIPアドレスがブロックされると、サイトの閲覧すらできなくなることがあります。テストは慎重に行いましょう。
- インフラ/NW視点: IPブロックは、サーバーを守るための正当な防御策です。回避策を講じる場合でも、サイトへの負荷を増大させないよう細心の注意を払い、あくまでサイト運営者の意図を尊重する姿勢が重要です。
4. 動的コンテンツとJavaScriptへの対応
requestsとBeautifulSoupは、サーバーから直接返されるHTMLコンテンツの解析には非常に強力です。しかし、昨今のWebサイトの多くはJavaScriptを用いて動的にコンテンツを生成しています。
-
requests/BeautifulSoupの限界: これらでは、JavaScriptが実行される前の「生のHTML」しか取得できません。JavaScriptによって後から読み込まれるコンテンツ(例: 無限スクロール、SPAなど)は、BeautifulSoupでは抽出できません。 -
解決策:
-
selenium/Playwright: これらは「ヘッドレスブラウザ」を操作し、JavaScriptを実行した結果のHTMLを取得できます。人間がブラウザで閲覧するのと同じようにコンテンツをレンダリングするため、動的なWebサイトのスクレイピングに適しています。 - APIの特定: 稀に、Webサイトが内部的に利用しているAPIを見つけ出し、直接そのAPIを叩くことでデータを取得できる場合があります。これは最も効率的ですが、APIの構造解析が必要であり、サイト側がAPIの仕様を変更するとスクレイピングも破綻しやすいです。
- Web開発視点: フロントエンド技術の進化がスクレイピングの難易度を上げています。最新のWeb技術に対応したツール選定と、JavaScriptの実行環境を考慮した実装が求められます。
-
5. HTML構造の変化への対応と堅牢性
Webサイトのデザインや機能は日々更新されます。それに伴い、HTMLの構造(クラス名、ID、タグのネストなど)も変化する可能性があります。
-
スクレイピングコードの脆弱性: 特定のセレクタ(例:
soup.find('div', class_='news-title').text)に依存している場合、HTML構造が少し変わるだけでコードが動作しなくなります。 -
解決策:
-
堅牢なセレクタの利用: 変化しにくいと思われる属性(例:
data-test-idのようなテスト用属性、IDなど)を利用する。 - 複数のセレクタのフォールバック: 複数のセレクタを試すロジックを実装し、一部が変更されても対応できるようにする。
- 定期的な監視とメンテナンス: スケジュール実行するスクレイピングジョブは、HTML構造の変更を検知するための監視メカニズム(例: 取得データが急減した際にアラートを出す)と、定期的なメンテナンスが不可欠です。
- ソフトスキル視点: チームでスクレイピングを運用する場合、HTML構造の変更があった際に誰が、どのように検知し、対応するかを明確な運用ルールとして定めておくことが重要です。
-
堅牢なセレクタの利用: 変化しにくいと思われる属性(例:
6. 認証が必要なサイトのスクレイピング
ログインが必要なサイトからデータを取得したい場合、認証プロセスを自動化する必要があります。
- 課題: ユーザー名とパスワードを送信し、セッション情報を維持する必要があります。
-
解決策:
-
requests.Session():requestsライブラリのSessionオブジェクトを利用すると、Cookieを自動的に保持してくれるため、ログイン後のセッションを維持しやすくなります。 - Cookie/トークンの利用: ログイン後のCookieや認証トークンを手動で取得し、それをヘッダーに含めてリクエストを送信する方法もあります。
- セキュリティ視点: 認証情報(ユーザー名、パスワード、セッショントークンなど)は非常に機密性の高い情報です。これらをコード内に直接ハードコードすることは避け、環境変数やセキュアな設定管理システム(例: HashiCorp Vault, AWS Secrets Manager)で管理するようにしましょう。最小権限の原則に基づき、スクレイピング専用のアカウントを作成することも検討します。
-
7. 取得データの保存と構造化
スクレイピングで取得したデータは、目的に応じて適切に保存・構造化する必要があります。
- 形式: JSONL、CSV、データベース(リレーショナルDB、NoSQL DB)など、用途に応じて最適な形式を選びます。
-
データベース設計:
- RDBMS (PostgreSQL, MySQLなど): 構造が固定されているデータや、複雑なクエリが必要な場合に適しています。事前にテーブルスキーマを設計し、正規化を考慮します。
- NoSQL DB (MongoDB, DynamoDBなど): 構造が可変なデータや、大量のデータを高速に保存・取得したい場合に適しています。
- パフォーマンス最適化: 大量のデータをデータベースに挿入する場合、1件ずつINSERTするよりも「バルクインサート(一括挿入)」を利用することで、I/O負荷を減らし、処理速度を大幅に向上させることができます。
- Web開発/DB視点: データモデルの設計は、スクレイピング後のデータ活用の成否を左右します。後工程(データクレンジング、AIファインチューニングなど)を意識した構造化が重要です。
8. 個人情報保護と法規制
スクレイピングの対象が、個人情報や機密性の高い情報である場合、GDPR(EU一般データ保護規則)やCCPA(カリフォルニア州消費者プライバシー法)、日本の個人情報保護法などの法規に抵触する可能性があります。
- 倫理的・法的側面: 公開されている情報であっても、個人の特定に繋がる情報や、プライバシーを侵害する可能性のある情報の収集・利用は、厳しく規制されています。また、著作権法上の「情報解析目的の複製(第30条の4)」の適用範囲についても正しく理解しておく必要があります。
- セキュリティ視点: 意図せず個人情報を取得してしまった場合は、速やかにそのデータを破棄し、取得経路を確認・修正する必要があります。データガバナンスとセキュリティポリシーの遵守が不可欠です。
まとめ:Webスクレイピングを実務で活かすために
Webスクレイピングは、インターネット上の膨大な情報を自動的に収集・加工し、AIファインチューニング用の貴重なデータセットへと変換するための非常に強力な技術です。しかし、その強力さゆえに、安易な利用は大きなリスクを伴います。
独学や実務の初期段階では、コードの書き方に目が行きがちですが、現場のシニアエンジニアとして特に伝えたいのは、**「技術的な側面だけでなく、倫理的、法的、そして運用面での配慮が不可欠である」**という点です。サイトの利用規約を読み、robots.txtに従い、サーバーに負荷をかけないように設計し、取得したデータの取り扱いには細心の注意を払う。これらは、単なる技術的なスキルセットを超えた、エンジニアとしての責任感とプロフェッショナリズムを示すものです。
Webスクレイピングのスキルを深掘りすることは、単にPythonのライブラリの使い方を学ぶだけでなく、Webの仕組み(HTTP、HTML、JavaScript)、ネットワークの基本、データベース設計、さらには法規制や倫理といった、多岐にわたる領域の知識と視点を習得する絶好の機会となります。
DokuProが常に提唱する「領域横断的な視点」こそが、Webスクレイピングという一見するとシンプルな技術の裏に潜む、真の複雑な課題を解決し、価値を生み出す力を育むのです。この経験を活かし、皆さんが責任感あるエンジニアとして成長していくことを期待しています。
エンジニアのスキルシェアプラットフォーム「DokuPro」
教えたい人と学びたい人を繋ぐDokuProでは、新規登録(先生・生徒)を募集中です。
詳細はこちら: https://dokupro.dev/