AI

llm-scraperによるAIを活用したウェブスクレイピング

llm-scraperでAIを搭載したウェブスクレーパーを構築し、構造化データを抽出し、LLMとTypeScriptを使用してスクレイピングコードを生成する方法をご覧ください。
6 分読
Web Scraping With llm-scraper

このガイドで、あなたは学ぶだろう:

  • llm-scraperとは
  • ステップ・バイ・ステップのウォークスルーで見る使い方
  • コード生成のための使い方
  • LLMベースのスクレイピングに代わる主な方法とは?
  • 主な限界とその克服法

さあ、飛び込もう!

llm-scraperとは?

llm-scraperはLLMを使ってあらゆるウェブページから構造化データを抽出するTypeScriptライブラリである。
サイトごとにカスタムパースロジックを書く代わりに、スキーマを定義するだけで、パッケージはLLMを使ってページのコンテンツを分析し、インテリジェントにスキーマを埋めてくれる。

このライブラリが最初にリリースされたのは2024年半ばなので、まだかなり新しい。しかし、GitHub上ではすでに4,000を超えるスターを獲得しており、その人気の速さを示している:

llm-scraperのGitHubでの進化

従来のスクレイパーでは破綻しがちな、動的で一貫性のないウェブサイト(eコマースなど)に最適です。そのようなシナリオでは、LLMスクレイピングが輝きます

llm-scraperがサポートする主な機能は以下の通りである:

  • 複数のLLMプロバイダーとの統合:ローカルモデル(OllamaやGGUFなど)やクラウドプロバイダー(OpenAIやVercel AI SDKなど)と連携。
  • スキーマベースのデータ抽出:Zodスキーマを使用して抽出したいデータを定義し、強力な構造と検証を行います。
  • 完全な型安全性:TypeScript用に設計されているため、コンパイル時に完全な型チェックを行うことができます。
  • Playwrightで構築:ブラウザの制御とページコンテンツの取得にPlaywrightを使用しています。
  • ストリーミングのサポート:完全な抽出が完了するのを待つ代わりに、スクレイピング中にオブジェクトをストリーミングできる。
  • コード生成:スキーマとターゲットに基づいてスクレイピングコードを動的に生成できます。
  • 複数のページ・コンテンツ・フォーマット・オプション:ページコンテンツをLLMに送信する方法を選択できます。

ウェブスクレイピングのためのllm-scraperの使い方

このチュートリアルでは、llm-scraperライブラリを使ってAIを搭載したスクレイパーを構築する方法を学びます。対象サイトは、ToScrapeウェブサイトのeコマース商品ページです:

ターゲット・サイト

Eコマースサイトのスクレイピングは厄介なので、これは素晴らしい例だ。ページ構造はしばしば変化するし、商品によってレイアウトや情報が異なることもある。そのため、静的な解析ロジックを書くのは難しく、あまり効果的ではない。したがって、AIは間違いなく助けになる。

LLMを搭載したスクレーパーを構築するには、以下の手順に従ってください!

前提条件

このチュートリアルに従うには、以下のものが必要である:

  • マシンにインストールされたNode.js
  • OpenAI APIキー(またはGroqのような同様のプロバイダーのキー)
  • TypeScriptと非同期プログラミングの基本的な理解

ステップ1:プロジェクトのセットアップ

始める前に、最新のLTSバージョンのNode.jsがローカルにインストールされていることを確認してください。インストールされていない場合は、公式サイトからダウンロードしてインストールしてください。

さて、スクレイパー用のプロジェクトを作成し、ターミナルでそのプロジェクトに移動する:

mkdir llm-scraper-project
cd llm-scraper-project

プロジェクト内で以下のコマンドを実行し、空のNode.jsプロジェクトを初期化する:

npm init -y

上記のコマンドで作成したpackage.jsonファイルを開き、以下の内容が含まれていることを確認する:

"type": "module"

プロジェクトのフォルダllm-scraper-projectを Visual Studio Codeなどのお気に入りのTypeScript IDEで読み込む。

次に、TypeScriptをdev依存としてインストールする:

npm install typescript --save-dev

TypeScriptをインストールした状態で、TypeScriptプロジェクトを初期化する:

npx tsc --init

プロジェクトのフォルダにtsconfig.jsonファイルが現れます。それを開き、以下のように置き換えてください:

{
  "compilerOptions": {
    "module": "ESNext",
    "target": "ESNext",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "skipLibCheck": true
  }
}

さて、プロジェクトにscraper.tsファイルを追加しよう:

llm-scraperプロジェクトのファイル構造

このファイルにはllm-scraperのデータ抽出ロジックが含まれることになる。スクリプトは非同期のTypeScriptロジックを使用するので、その内部で非同期関数を初期化する:

async function llmScraping() {
  // your LLM scraping logic...
}

llmScraping()

素晴らしい!これで完全にセットアップが完了し、AIを搭載したスクレーパーの構築を開始する準備が整った。

ステップ #2: スクレイピングされたライブラリのインストール

llm-scraperは以下の2つの追加ライブラリに依存して動作する:

  • Zod:TypeScriptファーストのスキーマ宣言・検証ライブラリ。
  • Playwright:Chromium、Firefox、WebKitブラウザを単一のAPIで自動化するライブラリ。

以下のコマンドでllm-scraperと一緒にインストールしてください:

npm install zod playwright llm-scraper

Playwrightには、(ブラウザのバイナリなど)追加の依存関係が必要です。それらをインストールしてください:

npx playwright install

さて、scraper.tsでZodとPlaywrightをインポートする:

import { z } from "zod"
import { chromium } from "playwright"
import LLMScraper from "llm-scraper"

素晴らしい!これでTypeScriptでLLMのWebスクレイピングを始めるのに必要なライブラリはすべて揃った。

ステップ3:OpenAIのセットアップ

llm-scraperはOpenAI、Groq、Ollama、GGUFなどいくつかのLLMプロバイダーをサポートしている。今回は OpenAI を使う。もしまだであれば、OpenAIのAPIキーを取得しておいてください。

まず、OpenAIのJavaScriptクライアントをインストールします:

npm install @ai-sdk/openai

そして、それをコードにインポートし、llmScraping()関数内でLLMモデルを初期化するために使用します:

// other imports...
import { openai } from "@ai-sdk/openai"

// ...

const llm = openai.chat("gpt-4o")

別の統合については、公式のllm-scraper`の ドキュメントを参照してください。

コードにOpenAIのキーをハードコーディングしないようにするには、dotenvをインストールしてください:

npm install dotenv

scraper.tsファイルにdotenvをインポートし、dotenv.config()を呼び出して環境変数をロードする:

// other imports...
import * as dotenv from "dotenv"

// ...

dotenv.config()

これにより、OpenAIのAPIキーのような環境変数を.envファイルから読み込むことができます。このように、プロジェクトに.envファイルを追加します:

プロジェクトに.envファイルを追加する

それを開いて、OpenAIのAPIキーを追加する:

OPENAI_API_KEY="<YOUR_OPENAI_KEY>"

置き換える をOpen AIキーの値に置き換えてください。

コード内でこの変数を手動で読み込む必要はない。なぜなら、@ai-sdk/openaiは自動的にOPENAI_KEY環境変数を読み込もうとするからです。

驚いた!LLM統合完了

ステップ #4: ターゲットページに接続する

llm-scraperは、ウェブページのHTMLコンテンツを抽出するために、ブラウザ自動化エンジンとしてPlaywrightに依存しています。始めるには、llmScraping() の中に以下のコードを追加してください:

  1. Chromiumブラウザの初期化
  2. 新しいページを開く
  3. Playwrightにターゲットページにアクセスするよう指示する。

でそれを達成する:

const browser = await chromium.launch()
const page = await browser.newPage()

await page.goto("https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html")

最後に、ブラウザを閉じてリソースを解放することを忘れないでください:

await page.close()
await browser.close()

このプロセスに慣れていない方は、Playwrightのウェブスクレイピングに関するガイドをお読みください。

ステップ5:データスキーマの定義

さて、llm-scraperは、特定のデータモデルで定義された構造化データを抽出するために、基礎となるLLMモデルにプロンプトを与え、Playwrightを介してページから抽出されたコンテンツ上で動作する。

そこでZodが登場し、TypeScriptでデータモデルを指定する手助けをする。スクレイピングしたデータのスキーマがどのように見えるべきかを理解するには、ブラウザで対象のサイトを開き、ページのトップレベルを分析することから始める:

対象ページのトップレベル

ここからは、以下のデータを抽出することに集中してほしい:

  • タイトル
  • 価格
  • 在庫状況
  • 数量
  • 説明

次に、ページの最後のセクションに移動する:

ターゲットページの最後のセクション

ここで、あなたは興味を持つだろう:

  • UPC(ユニバーサル・プロダクト・コード)
  • 製品タイプ
  • 税金
  • レビュー数

これをすべてまとめると、次のような製品スキーマになる:

const productSchema = z.object({
  title: z.string().describe("The name of the product"),
  price: z.string().describe("The price of the product, typically formatted as a string like '£19.99'"),
  stock: z.string().describe("The availability status of the product, such as 'In Stock' or 'Out of Stock'"),
  quantity: z.string().describe("The specific quantity of products available in stock"),
  description: z.string().describe("A detailed description of the product, including features and specifications"),
  upc: z.string().describe("The Universal Product Code (UPC) to uniquely identify the product"),
  productType: z.string().describe("The category or type of the product, such as 'Books', 'Clothing', etc."),
  tax: z.string().describe("Information about the applicable tax amount for the product"),
  reviews: z.number().describe("The number of reviews the product has received"),
})

ヒントLLMモデルがデータに対して何をすべきかを理解するのに役立ちます。

素晴らしい!これでllm-scraperのAIスクレイピングタスクを起動する準備ができました。

ステップ #6: スクレイピングタスクの実行

ステップ3で定義したLLMインテグレーションを使って、LLMScraperオブジェクトを作成する:

const scraper = new LLMScraper(llm)

これはllm-scraperライブラリが公開するメインオブジェクトで、AIを使ったスクレイピングタスクを実行する。

そして、次のようにスクレーパーを起動する:

const { data } = await scraper.run(page, productSchema, {
  format: "markdown",
})

formatパラメータは、ページ内容がどのようにLLMに渡されるかを定義します。指定できる値は

  • 「html":ページの生のHTML。
  • "text":ページから抽出されたすべてのテキストコンテンツ。
  • "markdown":Markdownに変換されたHTMLコンテンツ。
  • "クリーンアップ":ページから抽出されたテキストのクリーンアップ版。
  • "イメージ":ページのスクリーンショット。

:必要に応じて、コンテンツのフォーマットを制御するカスタム関数を提供することもできます。

新しいAIエージェントはなぜHTMLよりもMarkdownを選ぶのか」ガイドで述べたように、Markdownフォーマットを使用することは、トークンを節約し、スクレイピングプロセスをスピードアップするのに役立つため、賢い選択である。

最後に、scraper.run()関数は、期待するZodスキーマにマッチするオブジェクトを返します。

完璧!AIを使ったスクレイピング・タスクの完成だ。

ステップ#7:スクレイピングしたデータをエクスポートする

現在、スクレイピングされたデータはJavaScriptオブジェクトに保存されています。データへのアクセス、分析、共有を容易にするには、以下のようにJSONファイルにエクスポートします:

const jsonData = JSON.stringify(data, null, 4)
await fs.writeFile("product.json", jsonData, "utf8")

これには外部ライブラリは必要ない。以下のimportをscraper.tsファイルの先頭に追加してください:

import { promises as fs } from "fs"

ステップ8:すべてをまとめる

scraper.tsが含まれるようになった:

import { z } from "zod"
import { chromium } from "playwright"
import LLMScraper from "llm-scraper"
import { openai } from "@ai-sdk/openai"
import * as dotenv from "dotenv"
import { promises as fs } from "fs"

// load the environment variables from the local .env file
dotenv.config()

async function llmScraping() {
  // initialize the LLM engine
  const llm = openai.chat("gpt-4o")

  // launch a browser instance and open a new page
  const browser = await chromium.launch()
  const page = await browser.newPage()

  // navigate to the target e-commerce product page
  await page.goto("https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html")

  // define the product schema
  const productSchema = z.object({
    title: z.string().describe("The name of the product"),
    price: z.string().describe("The price of the product, typically formatted as a string like '£19.99'"),
    stock: z.string().describe("The availability status of the product, such as 'In Stock' or 'Out of Stock'"),
    quantity: z.string().describe("The specific quantity of products available in stock"),
    description: z.string().describe("A detailed description of the product, including features and specifications"),
    upc: z.string().describe("The Universal Product Code (UPC) to uniquely identify the product"),
    productType: z.string().describe("The category or type of the product, such as 'Books', 'Clothing', etc."),
    tax: z.string().describe("Information about the applicable tax amount for the product"),
    reviews: z.number().describe("The number of reviews the product has received"),
  })

  // create a new LLMScraper instance
  const scraper = new LLMScraper(llm)

  // run the LLM scraper
  const { data } = await scraper.run(page, productSchema, {
    format: "markdown", // or "html", "text", etc.
  })

  // conver the scraped data to a JSON string
  const jsonData = JSON.stringify(data, null, 4)
  // populate an output file with the JSON string
  await fs.writeFile("product.json", jsonData, "utf8")

  // close the page and the browser and release their resources
  await page.close()
  await browser.close()
}

llmScraping()

ご覧のように、llm-scraperは JavaScriptベースのスクレイピングスクリプトをわずかなコード行で定義することができます。

このコマンドでスクリプトをTypeScriptからJavaScriptにコンパイルする:

npx tsc

scraper.jsファイルがあなたのプロジェクトのフォルダに現れます。それを

node scraper.js

スクリプトの実行が終了すると、product.jsonというファイルがプロジェクトフォルダに表示されます。

それを開くと、このように表示される:

{
  "title": "A Light in the Attic",
  "price": "£51.77",
  "stock": "In Stock",
  "quantity": "22",
  "description": "It's hard to imagine a world without A Light in the Attic. This now-classic collection of poetry and drawings from Shel Silverstein celebrates its 20th anniversary with this special edition. Silverstein's humorous and creative verse can amuse the dowdiest of readers. Lemon-faced adults and fidgety kids sit still and read these rhythmic words and laugh and smile and love that Silverstein. Need proof of his genius? Rockabye Rockabye baby, in the treetop Don't you know a treetop Is no safe place to rock? And who put you up there, And your cradle, too? Baby, I think someone down here's Got it in for you. Shel, you never sounded so good.",
  "upc": "a897fe39b1053632",
  "productType": "Books",
  "tax": "£0.00",
  "reviews": 0
}

このファイルには、あなたがターゲットとした商品ページに表示された情報が正確に含まれています。ご覧のように、LLMのパワーのおかげで、カスタム解析ロジックを必要とせずにデータが抽出されました。よくやった!

おまけllm-scraper によるコード生成

llm-scraperは、スキーマが与えられた場合、基礎となるPlaywrightデータ解析ロジックを生成する機能も持っています。これはgenerate()関数によって可能です。

下のスニペットの例をご覧ください:

const { code } = await scraper.generate(page, productSchema)

ご覧のように、これはPlaywrightページ・オブジェクトとZodスキーマを受け取り、生成されたPlaywrightコードを含む文字列を返します。この場合、出力は

(function() {
function extractData() {
const title = document.querySelector('h1').innerText;
const price = document.querySelector('.price_color').innerText;
const stockText = document.querySelector('.instock.availability').innerText.trim();
const stock = stockText.includes('In stock') ? 'In Stock' : 'Out of Stock';
const quantityMatch = stockText.match(/\d+/);
const quantity = quantityMatch ? quantityMatch[0] : '0';
const description = document.querySelector('#product_description ~ p').innerText;
const upc = document.querySelector('th:contains("UPC") + td').innerText;
const productType = document.querySelector('th:contains("Product Type") + td').innerText;
const tax = document.querySelector('th:contains("Tax") + td').innerText;
const reviews = parseInt(document.querySelector('th:contains("Number of reviews") + td').innerText, 10);
    return {
        title,
        price,
        stock,
        quantity,
        description,
        upc,
        productType,
        tax,
        reviews
    };
}

const data = extractData();
console.log(data);
})()

そして、この生成されたJavaScriptコードをプログラムで実行し、その結果を解析することができる:

const result = await page.evaluate(code)
const data = schema.parse(result)

データ・オブジェクトには、前章のステップ#6で作成されたデータと同じ結果が含まれます。

llm-scraperLLMスクレイピングの代替手段

LLMを使ったスクレイピングに利用できるライブラリはllm-scraperだけではありません。他にも注目すべき代替ライブラリがある:

  • Crawl4AI: AIに対応した高速なウェブクローリングエージェントとデータパイプラインを構築するためのPythonライブラリです。柔軟性が高く、開発者が迅速かつ正確にデプロイできるように最適化されています。Crawl4AIのスクレイピングに関するチュートリアルで、実際に動作する様子をご覧いただけます。
  • ScrapeGraphAI: PythonのWebスクレイピング・ライブラリで、LLMと直接グラフ・ロジックを組み合わせて、Webサイトやローカル・ドキュメント(XML、HTML、JSON、Markdownなど)のスクレイピング・パイプラインを構築する。ScrapeGraphAIを使ったスクレイピングのガイドで確認してください。

ウェブスクレイピングのこのアプローチの限界

この記事で使用したターゲットサイトToScrapeは、その名の通り、スクレイピングスクリプトを歓迎するスクレイピングサンドボックスだ。残念ながら、llm-scraperを実世界のウェブサイトに対して使用する場合、事態はより困難になる可能性が高い…。

なぜか?なぜなら、Eコマース企業やオンライン・ビジネスは、自社のデータがどれほど貴重なものであるかを知っており、その保護のために多大な努力を払っているからだ。たとえそのデータが商品ページで公開されていたとしても同様だ。

その結果、ほとんどのeコマース・プラットフォームは、自動化されたクローラーをブロックするために、アンチボットとアンチスクレイピング対策を実装しています。これらの技術は、llm-scraperと同じように、Playwrightのようなブラウザ自動化ツールに基づくスクレイパーさえも止めることができる。

悪名高いアマゾンのCAPTCHAのような防御について話しているのだ:

アマゾンのCAPTCHA認証画面で、歪んだテキスト画像に表示された文字を入力するようユーザーに求める。説明と、続けるか別の画像を試すかのオプションが含まれている。

PlaywrightでCAPTCHAを迂回できたとしても、自動化されすぎたリクエストによるIPバンなど、他の課題によってスクレイピング作業が停止される可能性がある。

この時点で、解決策はスクリプトをより複雑にするために際限なく微調整することではない。適切なツールを使うことだ。

PlaywrightをScraping Browserのようなウェブスクレイピング専用に設計されたブラウザと統合することで、すべてがより簡単になります。このソリューションは、スクレイピング用に最適化されたクラウドベースのブラウザです。IPローテーション、自動再試行、高度なアンチボットバイパスメカニズム、さらにはビルトインCAPTCHA解決まで、インフラを自分で管理することなく処理することができる。

スクレイピングブラウザを他のブラウザと同じようにllm-scraperのPlaywrightと統合します

結論

このブログポストでは、llm-scraperの特徴と、それを使ってTypeScriptでAIを搭載したスクレイピングスクリプトを構築する方法を学んだ。LLMとの統合のおかげで、複雑で動的なページ構造を持つサイトをスクレイピングすることができます。

説明したように、ブロックされるのを避ける最も効果的な方法は、組み込みのCAPTCHAソルバーと他の多くのアンチボットバイパス機能を備えたBright Dataのスクレイピングブラウザと一緒に利用することである。

このソリューションに基づいて直接AIエージェントを構築することに興味がある方は、Agent Browserをチェックしてみてください。このソリューションは、ブロックされることのないリモートブラウザ上でエージェント主導のワークフローを実行します。無限にスケーラブルで、世界で最も信頼性の高いプロキシネットワークを搭載しています。

今すぐBright Dataの無料アカウントを作成し、データおよびスクレイピングソリューションについてご確認ください!

クレジットカードは必要ありません