従来のウェブスクレイピング手法は、ウェブサイトのレイアウトが変わったり、ボット対策が厳しくなったりすると、しばしば破綻します。このガイドでは、LLaMA 3-Metaの強力なオープンウェイト言語モデルを使用して、ほぼすべてのウェブサイトから構造化データを抽出し、クリーンで使用可能なJSONに変換する、より弾力性のあるAIを搭載したアプローチを学びます。
始めよう。
なぜウェブスクレイピングにLLaMA 3を使うのか?
LLaMA 3(2024年4月リリース)は、メタ社のオープンウエイトのラージ言語モデルで、8Bから405Bのパラメータ・サイズで利用できる。幅広いユースケースとハードウェア容量をサポートしている。その後にリリースされたLLaMA 3.1、3.2、3.3では、パフォーマンスと文脈理解が大幅に向上しています。
従来のウェブスクレイピング手法は、XPathやCSSのような静的セレクタに依存しており、ウェブサイトの構造が変わると簡単に壊れてしまいます。対照的に、LLaMA 3は、人間のようにコンテンツを文脈的に理解することで、インテリジェントなデータ抽出を可能にします。
これは理想的なことだ:
- アマゾンなどのeコマースサイト
- データ解析
- ウェブサイトが更新されるたびに壊れることのない、より弾力性のあるスクレーパーの作成
- スクレイピングしたデータを自社環境内に保持する-機密情報には不可欠
ウェブスクレイピングにAIを活用する方法について、詳しくはこちらをご覧ください。
前提条件
LLMのウェブスクレイピングに飛び込む前に、以下のことを確認してください:
- Python3のインストール
- Pythonの基本的な知識(専門家である必要はありません)
- 互換性のあるオペレーティングシステム: – macOS(macOS 11 Big Sur以降が必要) – Linux – Windows(Windows 10以降が必要)
- 十分なハードウェアリソース(以下のモデル選択の詳細を参照)
Ollamaのインストール
Ollamaは、大規模な言語モデルのダウンロード、セットアップ、ローカルでの実行を簡素化する軽量ツールである。
始めよう:
- Ollamaの公式サイトを見る
- お使いのオペレーティングシステム用のアプリケーションをダウンロードしてインストールします。
- 重要インストール中、Ollamaはターミナルコマンドを実行するよう促しますが、まだ実行しないでください。まずは正しいモデルのバージョンを選択しましょう。
LLaMAモデルの選択
まずはOllamaのモデル・ライブラリーをご覧いただき、お客様のハードウェアとユースケースに最適なLLaMAバージョンをお選びください。
ほとんどのユーザーにとって、llama3.1:8b
はパフォーマンスと効率のバランスが最も取れています。軽量で高性能で、約4.9GBのディスクスペースと6-8GBのRAMを必要とします。ほとんどの最新のラップトップでスムーズに動作する。
よりパワフルなマシンで作業しており、より大きな推論能力やコンテキストの長さが必要な場合は、70Bや
405Bの
ような大型モデルへのスケールアップを検討してください。これらは、より多くのメモリと計算能力を必要とします。
モデルの引き上げと実行
LLaMA 3.1(8B)モデルをダウンロードして初期化するには、以下のコマンドを実行します:
ollama run llama3.1:8b
モデルがダウンロードされると、簡単な対話形式のプロンプトが表示されます:
>>> Send a message (/? for help)
簡単なクエリーでモデルをテストできます:
>>> who are you?
I am LLaMA, *an AI assistant developed by Meta AI...*
上記のような正常な応答が返ってくれば、そのモデルが正しくインストールされていることが確認できる。プロンプトを終了するには、/bye
と入力する。
次に、Ollamaサーバーを起動する:
ollama serve
このコマンドはhttp://127.0.0
.1:11434/、ローカルのOllamaインスタンスを起動する。
サーバーはバックグラウンドで実行し続ける必要があるので、このターミナルウィンドウは開いたままにしておくこと。
Ollamaは実行中です」というメッセージが表示されるはずです。
LLMを搭載したAmazonスクレイパーの構築
このセクションでは、Amazonから商品の詳細を抽出するスクレーパーを構築します。Amazonは、そのダイナミックなコンテンツと強力なボット対策により、最も困難なターゲットの1つです。
私たちは次のような重要な詳細を抽出する:
- 商品名
- 現在/元の価格
- 割引
- 評価とレビュー
- 概要と特徴
- 在庫とASIN
AIを活用した多段階ワークフロー
従来のスクレイピング、特にAmazonのような複雑なeコマースサイトでのスクレイピングの限界を克服するために、LLaMAを搭載したスクレイパーは、スマートで多段階のワークフローに従っています:
- ブラウザの自動化– Seleniumを使用してページをロードし、動的コンテンツをレンダリングする。
- HTML抽出– 商品の詳細を含むコンテナを特定し、抽出します。
- Markdown変換– トークン数を減らし、LLMの効率を向上させるためにHTMLをMarkdownに変換します。
- LLM処理– LLaMAで構造化プロンプトを使用して、クリーンで構造化されたJSONを抽出する。
- 出力処理– 下流での使用や分析のために、抽出されたJSONを保存します。
以下は、ワークフローの視覚的な内訳である:
では、そのプロセスを順を追って見ていこう。これらの例では、そのシンプルさと人気のためにPythonを使用していますが、JavaScriptや他のお好みの言語でも同様の結果を得ることができることに注意してください。
ステップ1 – 必要なライブラリのインストール
まず、必要なPythonライブラリをインストールする:
pip install requests selenium webdriver-manager markdownify
requests
– LLMサービスにAPIコールを送信するための最適なPython HTTPクライアントselenium
– ブラウザを自動化し、JavaScriptを多用するウェブサイトに最適。webdriver-manager
– 正しいChromeDriverのバージョンを自動的にダウンロードして管理するmarkdownify
– HTML を Markdown に変換する
ステップ2 – ヘッドレス・ブラウザの初期化
Seleniumを使ってヘッドレスブラウザをセットアップする:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
options = Options()
options.add_argument("--headless")
driver = webdriver.Chrome(
service=Service(ChromeDriverManager().install()),
options=options
)
ステップ3 – 製品HTMLを抽出する
アマゾンの商品詳細は、動的にレンダリングされ
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver, 15)
product_container = wait.until(
EC.presence_of_element_located((By.ID, "ppd"))
)
# Extract the full HTML of the product container
page_html = product_container.get_attribute("outerHTML")
このアプローチだ:
- JavaScriptでレンダリングされたコンテンツ(価格や評価など)を待つ
- ヘッダー、フッター、サイドバーを無視し、関連する製品セクションのみを対象とする。
PythonでAmazonの商品データをスクレイピングする方法の完全ガイドをご覧ください。
ステップ4 – HTMLをMarkdownに変換する
アマゾンのページには、LLMが処理するには非効率的な、深くネストされたHTMLが含まれています。重要な最適化は、このHTMLをきれいなMarkdownに変換することで、トークン数を劇的に減らし、理解度を向上させる。
スクリプトを実行すると、amazon_page.htmlと
amazon_page.mdの
2つのファイルが生成されます。両方をトークン計算ツールに貼り付けて、トークン数を比較してみてください。
以下に示すように、HTMLには約270,000のトークンが含まれている:
Markdownバージョン?わずか~11,000トークン:
この96%の削減は、次のことにつながる:
- コスト効率– トークンの数が少なければ少ないほど、APIコストやコンピュート・コストが低くなります。
- 処理の高速化– 入力データが少ない=LLMの応答が速い
- 精度の向上– よりクリーンでフラットなテキストは、モデルが構造化データをより正確に抽出するのに役立ちます。
AIエージェントがHTMLよりもMarkdownを好む理由については、こちらをお読みください。
ここでは、Pythonで変換を行う方法を説明する:
from markdownify import markdownify as md
clean_text = md(page_html, heading_style="ATX")
ステップ5 – データ抽出プロンプトの作成
よく構造化されたプロンプトは、LLMから一貫性のあるきれいなJSON出力を得るために重要です。以下は、定義済みのフォーマットで有効なJSONのみを返すようにモデルに指示するプロンプトです:
PROMPT = (
"You are an expert Amazon product data extractor. Your task is to extract product data from the provided content. "
"Return ONLY valid JSON with EXACTLY the following fields and formats:\n\n"
"{\n"
' "title": "string – the product title",\n'
' "price": number – the current price (numerical value only)",\n'
' "original_price": number or null – the original price if available,\n'
' "discount": number or null – the discount percentage if available,\n'
' "rating": number or null – the average rating (0–5 scale),\n'
' "review_count": number or null – total number of reviews,\n'
' "description": "string – main product description",\n'
' "features": ["string"] – list of bullet point features,\n'
' "availability": "string – stock status",\n'
' "asin": "string – 10-character Amazon ID"\n'
"}\n\n"
"Return ONLY the JSON without any additional text."
)
ステップ6 – LLM APIを呼び出す
Ollamaがローカルで動作している場合、MarkdownテキストをHTTP API経由でLLaMAインスタンスに送ることができる:
import requests
import json
response = requests.post(
"<http://localhost:11434/api/generate>",
json={
"model": "llama3.1:8b",
"prompt": f"{PROMPT}\n\n{clean_text}",
"stream": False,
"format": "json",
"options": {
"temperature": 0.1,
"num_ctx": 12000,
},
},
timeout=250,
)
raw_output = response.json()["response"].strip()
product_data = json.loads(raw_output)
それぞれのオプションは何をするのか:
temperature
– 0.1に設定すると、決定論的な出力が得られます(JSONフォーマットに最適です)。num_ctx
– コンテキストの最大長を定義します。12,000トークンは、ほとんどのアマゾンの商品ページで十分です。stream
–Falseの
場合、APIは処理後の完全なレスポンスを返す。format
– 出力形式(JSON)を指定します。model
– 使用するLLaMAのバージョンを示します。
変換されたMarkdownには通常約11,000トークンが含まれるため、それに応じてコンテキスト・ウィンドウ(num_ctx
)を設定することが重要です。この値を増やすと長い入力を処理できるようになりますが、RAMの使用量が増え、処理が遅くなります。商品ページが特に長い場合や、それをサポートする計算リソースがある場合にのみ、コンテキストの上限を増やしてください。
ステップ7 – 結果を保存する
最後に、構造化された商品データをJSONファイルに保存する:
with open("product_data.json", "w", encoding="utf-8") as f:
json.dump(product_data, f, indent=2, ensure_ascii=False)
ステップ8:スクリプトの実行
スクレイパーを実行するには、アマゾンの商品URLを指定し、スクレイピング機能を呼び出す:
if __name__ == "__main__":
url = "<https://www.amazon.com/Black-Office-Chair-Computer-Adjustable/dp/B00FS3VJAO>"
# Call your function to scrape and extract product data
scrape_amazon_product(url)
ステップ9 – フルコードの例
以下は、すべてのステップを一貫したエンド・ツー・エンドのワークフローにまとめた完全なPythonスクリプトである:
import json
import logging
import time
from typing import Final, Optional, Dict, Any
import requests
from markdownify import markdownify as html_to_md
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from webdriver_manager.chrome import ChromeDriverManager
# Configuration constants
LLM_API_CONFIG: Final[Dict[str, Any]] = {
"endpoint": "<http://localhost:11434/api/generate>",
"model": "llama3.1:8b",
"temperature": 0.1,
"context_window": 12000,
"stream": False,
"timeout_seconds": 220,
}
DEFAULT_PRODUCT_DATA: Final[Dict[str, Any]] = {
"title": "",
"price": 0.0,
"original_price": None,
"discount": None,
"rating": None,
"review_count": None,
"description": "",
"features": [],
"availability": "",
"asin": "",
}
PRODUCT_DATA_EXTRACTION_PROMPT: Final[str] = (
"You are an expert Amazon product data extractor. Your task is to extract product data from the provided content. "
"Return ONLY valid JSON with EXACTLY the following fields and formats:\n\n"
"{\n"
' "title": "string - the product title",\n'
' "price": number - the current price (numerical value only),\n'
' "original_price": number or null - the original price if available,\n'
' "discount": number or null - the discount percentage if available,\n'
' "rating": number or null - the average rating (0-5 scale),\n'
' "review_count": number or null - total number of reviews,\n'
' "description": "string - main product description",\n'
' "features": ["string"] - list of bullet point features,\n'
' "availability": "string - stock status",\n'
' "asin": "string - 10-character Amazon ID"\n'
"}\n\n"
"Return ONLY the JSON without any additional text."
)
# Configure logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s",
handlers=[logging.StreamHandler()],
)
def initialize_web_driver(headless: bool = True) -> webdriver.Chrome:
"""Initialize and return a configured Chrome WebDriver instance."""
options = Options()
if headless:
options.add_argument("--headless=new")
service = Service(ChromeDriverManager().install())
return webdriver.Chrome(service=service, options=options)
def fetch_product_container_html(product_url: str) -> Optional[str]:
"""Retrieve the HTML content of the Amazon product details container."""
driver = initialize_web_driver()
try:
logging.info(f"Accessing product page: {product_url}")
driver.set_page_load_timeout(15)
driver.get(product_url)
# Wait for the product container to appear
container = WebDriverWait(driver, 5).until(
EC.presence_of_element_located((By.ID, "ppd"))
)
return container.get_attribute("outerHTML")
except Exception as e:
logging.error(f"Error retrieving product details: {str(e)}")
return None
finally:
driver.quit()
def extract_product_data_via_llm(markdown_content: str) -> Optional[Dict[str, Any]]:
"""Extract structured product data from markdown text using LLM API."""
try:
logging.info("Extracting product data via LLM API...")
response = requests.post(
LLM_API_CONFIG["endpoint"],
json={
"model": LLM_API_CONFIG["model"],
"prompt": f"{PRODUCT_DATA_EXTRACTION_PROMPT}\n\n{markdown_content}",
"format": "json",
"stream": LLM_API_CONFIG["stream"],
"options": {
"temperature": LLM_API_CONFIG["temperature"],
"num_ctx": LLM_API_CONFIG["context_window"],
},
},
timeout=LLM_API_CONFIG["timeout_seconds"],
)
response.raise_for_status()
raw_output = response.json()["response"].strip()
# Clean JSON output if it's wrapped in markdown code blocks
if raw_output.startswith(("```json", "```")):
raw_output = raw_output.split("```")[1].strip()
if raw_output.startswith("json"):
raw_output = raw_output[4:].strip()
return json.loads(raw_output)
except requests.exceptions.RequestException as e:
logging.error(f"LLM API request failed: {str(e)}")
return None
except json.JSONDecodeError as e:
logging.error(f"Failed to parse LLM response: {str(e)}")
return None
except Exception as e:
logging.error(f"Unexpected error during data extraction: {str(e)}")
return None
def scrape_amazon_product(
product_url: str, output_file: str = "product_data.json"
) -> None:
"""Scrape an Amazon product page and save extracted data along with HTML and Markdown to files."""
start_time = time.time()
logging.info(f"Starting scrape for: {product_url}")
# Step 1: Fetch product page HTML
product_html = fetch_product_container_html(product_url)
if not product_html:
logging.error("Failed to retrieve product page content")
return
# Optional: save HTML for debugging
with open("amazon_product.html", "w", encoding="utf-8") as f:
f.write(product_html)
# Step 2: Convert HTML to Markdown
product_markdown = html_to_md(product_html)
# Optional: save Markdown for debugging
with open("amazon_product.md", "w", encoding="utf-8") as f:
f.write(product_markdown)
# Step 3: Extract structured data via LLM
product_data = (
extract_product_data_via_llm(product_markdown) or DEFAULT_PRODUCT_DATA.copy()
)
# Step 4: Save JSON results
try:
with open(output_file, "w", encoding="utf-8") as json_file:
json.dump(product_data, json_file, indent=2, ensure_ascii=False)
logging.info(f"Successfully saved product data to {output_file}")
except IOError as e:
logging.error(f"Failed to save JSON results: {str(e)}")
elapsed_time = time.time() - start_time
logging.info(f"Completed in {elapsed_time:.2f} seconds")
if __name__ == "__main__":
# Example usage
test_url = (
"<https://www.amazon.com/Black-Office-Chair-Computer-Adjustable/dp/B00FS3VJAO>"
)
scrape_amazon_product(test_url)
スクリプトが正常に実行されると、抽出された商品データがproduct_data.jsonという
名前のファイルに保存されます。出力は次のようになります:
{
"title": "Home Office Chair Ergonomic Desk Chair Mesh Computer Chair with Lumbar Support Armrest Executive Rolling Swivel Adjustable Mid Back Task Chair for Women Adults, Black",
"price": 36.98,
"original_price": 41.46,
"discount": 11,
"rating": 4.3,
"review_count": 58112,
"description": 'Office chair comes with all hardware and tools, and is easy to assemble in about 10–15 minutes. The high-density sponge cushion offers flexibility and comfort, while the mid-back design and rectangular lumbar support enhance ergonomics. All components are BIFMA certified, supporting up to 250 lbs. The chair includes armrests and an adjustable seat height (17.1"–20.3"). Its ergonomic design ensures a perfect fit for long-term use.',
"features": [
"100% mesh material",
"Quick and easy assembly",
"High-density comfort seat",
"BIFMA certified quality",
"Includes armrests",
"Ergonomic patented design",
],
"availability": "In Stock",
"asin": "B00FS3VJAO",
}
ほら!ごちゃごちゃしたHTMLがきれいなJSONに生まれ変わる。これがウェブスクレイピングにおけるLLMのマジックだ。
ボット対策を克服する
上記のウェブスクレイピング・ボットを実行すると、CAPTCHAチャレンジのようなアマゾンのボット対策に遭遇する可能性が高い:
これは重要な限界を浮き彫りにしている:私たちのLLaMAベースのワークフローはHTMLの解析に優れていますが、高度なボット対策が施されたサイトでは、コンテンツへのアクセスはまだ困難です。
これを克服するには、Amazon CAPTCHAを回避し、その他のウェブスクレイピングの課題に対処する必要がある。
Bright Dataのスクレイピングブラウザは、従来のツールが失敗するような最も保護されたウェブサイトでも確実にロックを解除するなど、現代のウェブ環境の複雑さを処理するための専用ソリューションです。
さらに詳しくスクレイピング・ブラウザとヘッドレス・ブラウザの比較
ブライトデータスクレイピングブラウザを使う理由
Bright Data Scraping Browserは、最新のウェブスクレイピングプロジェクトをスケーリングするために構築された、プロキシインフラと高度なブロック解除機能を内蔵したヘッドレス、クラウドベースのブラウザです。Bright DataUnlockerスクレイピングスイートの一部です。
開発者やデータチームがこれを選ぶ理由は以下の通りだ:
- 信頼できるTLSフィンガープリントとステルス回避技術
- 150M以上のIPプロキシネットワークによる内蔵IPローテーション
- 自動CAPTCHA解決
- インフラストラクチャの削減 – コストのかかるクラウドのセットアップや継続的なメンテナンスが不要になります。
- Playwright、Puppeteer、Seleniumのネイティブサポート
- 大量データ抽出のための無制限のスケーラビリティ
最大の特徴は?わずか数行のコードで既存のワークフローに統合できる。
クラウドベースのウェブスクレイピングに移行する企業が増えている理由をお読みください。
スクレイピング・ブラウザの設定
スクレイピング・ブラウザを始めるには:
Bright Dataアカウントを作成し(新規ユーザーは支払い方法を追加した後、5ドルのクレジットを受け取ります)、ダッシュボードで「Proxies & Scraping」に進み、「Get started」をクリックします。
新しいゾーン(例:test_browser)を作成し、プレミアムドメインや CAPTCHAソルバーなどの機能を有効にします。
次に、ダッシュボードからSeleniumのURLをコピーします。
スクレイピング・ブラウザ用にコードを修正する
スクレイピング・ブラウザ経由で接続するようにinitialize_web_driver
関数を更新する:
from selenium.webdriver import Remote
from selenium.webdriver.chrome.options import Options as ChromeOptions
from selenium.webdriver.chromium.remote_connection import ChromiumRemoteConnection
SBR_WEBDRIVER = "<https://username:password@host>:port"
def initialize_web_driver():
options = ChromeOptions()
sbr_connection = ChromiumRemoteConnection(SBR_WEBDRIVER, "goog", "chrome")
driver = Remote(sbr_connection, options=options)
return driver
これであなたのスクレイパーはブライトデータのインフラを経由し、Amazonやその他のボット対策システムを簡単に処理できるようになりました。
より高度な機能については、スクレイピング・ブラウザのドキュメントをご覧ください。
次のステップと代替案
LLaMAを搭載したスクレーパーの機能を拡張したり、他の実装を検討するために、以下の改善や代替案を検討してください。
- スクリプトを再利用可能にする:柔軟に使用できるように、URLとプロンプトをコマンドライン引数として渡せるようにする。
- 認証情報を保護するスクレイピング・ブラウザの認証情報を
.env
ファイルに保存し、python-dotenvを使って
安全にロードします。 - 複数ページのサポートを追加する:複数ページをクロールし、ページネーションを処理するロジックを実装する。
- より多くのウェブサイトをスクレイピング– Scraping Browserの検知防止機能を使って、他のeコマース・プラットフォームをスクレイピングする。
- Googleサービスからのデータ抽出–Google Flights、Google Search、Google Trends専用のスクレイパーを構築するか、Bright DataのSERP APIを使用してすぐに使える検索データを取得します。
マネージド・ソリューションがお好きな方、あるいは他のLLM主導の方法を模索したい方は、以下のオプションが適しているかもしれません:
結論
このガイドでは、LLaMA 3を使用して弾力性のあるウェブスクレーパーを構築するための強固な基盤を提供します。大規模な言語モデルの推論機能と高度なスクレイピングツールを組み合わせることで、最小限の労力で複雑なウェブサイトから構造化データを抽出することができます。
ウェブスクレイピングにおいて、検知やブロックを避けることは最大の課題の一つです。Bright Data Scraping Browserは、ダイナミックレンダリング、フィンガープリンティング、アンチボットプロテクションを自動的に処理することで、この問題に対処します。これは、スケーラブルなデータ抽出をサポートするために設計された、より広範なツール群の一部です:
- プロキシ・サービス–1億5000万以上の家庭用IPにアクセスし、地域制限を回避
- Web Scraper API– 専用エンドポイントを介して100以上の人気ウェブサイトから構造化データを抽出します。
- Web Unlocking API– アンチスクレイピングシステムをバイパスして、あらゆるURLから完全にレンダリングされたHTMLを取得します。
- SERP API– すべての主要検索エンジンからリアルタイムの検索結果を収集します。
今すぐ登録して、Bright Dataのスクレイピングおよびプロキシツール一式を無料でお試しください!
クレジットカードは必要ありません