0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「最大10件」と頼んだのに40件取れたので、AIに生成コードを直させた話【Bright Data Scraper Studio】

0
Last updated at Posted at 2026-08-10

PR

本記事はBright Dataの企画に参加し、実際にScraper Studioを操作して執筆しています。本文中の評価は、2026年7月時点で筆者が検証した結果に基づきます。

はじめに

新しいサイトをスクレイピングするたびに、HTMLを開いて、セレクタを探して、コードを書いて、動かなければまたDevToolsへ戻る。

対象サイトが増えると、セレクタ調査だけでなく、定期実行やAPI化まで含めて地味に重くなります。

そこで今回は、URLと自然言語からスクレイパーを生成できるBright DataScraper Studioを実際に使いました。

最初はスクレイピング練習用サイトで基本的な生成能力を確認し、その後、筆者が普段から読んでいるGIGAZINEを対象に、日本語の指示でも動くか試します。

結果だけ先に書くと、スクレイパーの生成と実行はかなり早く終わりました。

ただし、すべてが一発で意図どおりになったわけではありません。

「最大10件」と指定したのに、40件取得されました。

その後、生成されたJavaScriptを確認し、Self-Healing機能に修正を頼み、差分を見てから反映したところ、10件へ制限できました。

この記事では、うまくいった部分だけでなく、実際に引っかかった箇所もそのまま載せます。

今回確認したこと

主に次の点を確認しました。

  • URLと自然言語からスクレイパーを作れるか
  • 英語だけでなく日本語の指示も解釈できるか
  • 生成されたスキーマとJavaScriptを確認、修正できるか
  • AIによるコード修正を差分確認してから反映できるか
  • JSON以外の形式でも結果を出力できるか
  • 定期実行やAPI利用へつなげられるか

検証対象は次の2サイトです。

対象 目的
Books to Scrape 基本的な抽出と型変換を確認する
GIGAZINE 日本語の実在サイトでも使えるか確認する

GIGAZINEではトップページのみを対象とし、個別記事ページは開いていません。

Scraper Studioを開く

Bright Dataの管理画面から「スクレーパー」を開き、右上の新規作成からAIによる作成画面へ進みます。

image.png

新規作成画面では、対象URLと追加指示を入力できます。

image.png

まずは英語で基本的な能力を試す

最初から日本語と実在サイトを使うと、失敗したときに原因を切り分けにくくなります。

そこで、まずはスクレイピング練習用のBooks to Scrapeを対象に、英語で指示しました。

対象URLは次のとおりです。

https://books.toscrape.com/

入力した指示は次の内容です。

Extract every book shown on the current page.

Return one record per book with these fields:

・title: book title
・price_gbp: price as a number without the £ symbol
・availability: stock availability text, trimmed
・rating: star rating as an integer from 1 to 5
・product_url: absolute URL to the book detail page
・image_url: absolute URL to the book cover image

Requirements:

・Keep the field names exactly as written above.
・Return all books displayed on the current page.
・Do not return relative URLs.
・Do not include extra fields.

AI Agentはすぐにコードを書き始めるのではなく、一覧ページだけを取得するのか、各書籍の詳細ページも開くのか、ページネーションを行うのかを確認してきました。

今回は最小構成の検証なので、次のように回答しました。

Extract data only from the listing page.

Do not open each book's detail page.

For this first test, scrape only the first page and return all books shown on it.

image.png

勝手に全ページを巡回せず、取得範囲を聞いてきたのは好印象でした。ページロード数や対象範囲を意図せず増やしにくくなります。

生成されたスキーマを確認する

指示の後、AI Agentが出力スキーマを生成しました。

image.png

生成された主な構造は次のとおりです。

{
  "books": [
    {
      "title": "text",
      "price_gbp": "number",
      "availability": "text",
      "rating": "number",
      "product_url": "url",
      "image_url": "url"
    }
  ]
}

価格は数値、評価も数値、商品ページと画像はURL型として定義されました。

各フィールドの説明には、取得に使うCSSセレクタや、星評価のOneからFiveを1から5へ変換する方針も書かれていました。

この段階では手動修正を行わず、そのまま承認しました。

初回実行で20件取得できた

生成されたスクレイパーを実行すると、トップページに表示されていた20冊を取得できました。

最初のレコードは次のような形です。

{
  "title": "A Light in the Attic",
  "price_gbp": 51.77,
  "availability": "In stock",
  "rating": 3,
  "product_url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
  "image_url": "https://books.toscrape.com/media/cache/2c/da/2cdad67c44b002e7ead0cc35693c0e8b.jpg"
}

確認した範囲では、次の条件を満たしていました。

・20件すべて取得
・指定した6項目を出力
・価格から£を除去して数値化
・評価を1から5の数値へ変換
・商品URLと画像URLを絶対URL化

練習用サイトとはいえ、最初の生成で期待した形まで持っていけました。

PR

本記事はBright Dataの企画に参加し、実際にScraper Studioを操作して執筆しています。本文中の評価は、2026年7月時点で筆者が検証した結果に基づきます。

はじめに

新しいサイトをスクレイピングするたびに、HTMLを開いて、セレクタを探して、コードを書いて、動かなければまたDevToolsへ戻る。

対象サイトが増えると、セレクタ調査だけでなく、定期実行やAPI化まで含めて地味に重くなります。

そこで今回は、URLと自然言語からスクレイパーを生成できるBright DataScraper Studioを実際に使いました。

最初はスクレイピング練習用サイトで基本的な生成能力を確認し、その後、筆者が普段から読んでいるGIGAZINEを対象に、日本語の指示でも動くか試します。

結果だけ先に書くと、スクレイパーの生成と実行はかなり早く終わりました。

ただし、すべてが一発で意図どおりになったわけではありません。

「最大10件」と指定したのに、40件取得されました。

その後、生成されたJavaScriptを確認し、Self-Healing機能に修正を頼み、差分を見てから反映したところ、10件へ制限できました。

この記事では、うまくいった部分だけでなく、実際に引っかかった箇所もそのまま載せます。

今回確認したこと

主に次の点を確認しました。

  • URLと自然言語からスクレイパーを作れるか
  • 英語だけでなく日本語の指示も解釈できるか
  • 生成されたスキーマとJavaScriptを確認、修正できるか
  • AIによるコード修正を差分確認してから反映できるか
  • JSON以外の形式でも結果を出力できるか
  • 定期実行やAPI利用へつなげられるか

検証対象は次の2サイトです。

対象 目的
Books to Scrape 基本的な抽出と型変換を確認する
GIGAZINE 日本語の実在サイトでも使えるか確認する

GIGAZINEではトップページのみを対象とし、個別記事ページは開いていません。

Scraper Studioを開く

Bright Dataの管理画面から「スクレーパー」を開き、右上の新規作成からAIによる作成画面へ進みます。

image.png

新規作成画面では、対象URLと追加指示を入力できます。

image.png

まずは英語で基本的な能力を試す

最初から日本語と実在サイトを使うと、失敗したときに原因を切り分けにくくなります。

そこで、まずはスクレイピング練習用のBooks to Scrapeを対象に、英語で指示しました。

対象URLは次のとおりです。

https://books.toscrape.com/

入力した指示は次の内容です。

Extract every book shown on the current page.

Return one record per book with these fields:

・title: book title
・price_gbp: price as a number without the £ symbol
・availability: stock availability text, trimmed
・rating: star rating as an integer from 1 to 5
・product_url: absolute URL to the book detail page
・image_url: absolute URL to the book cover image

Requirements:

・Keep the field names exactly as written above.
・Return all books displayed on the current page.
・Do not return relative URLs.
・Do not include extra fields.

AI Agentはすぐにコードを書き始めるのではなく、一覧ページだけを取得するのか、各書籍の詳細ページも開くのか、ページネーションを行うのかを確認してきました。

今回は最小構成の検証なので、次のように回答しました。

Extract data only from the listing page.

Do not open each book's detail page.

For this first test, scrape only the first page and return all books shown on it.

image.png

勝手に全ページを巡回せず、取得範囲を聞いてきたのは好印象でした。ページロード数や対象範囲を意図せず増やしにくくなります。

生成されたスキーマを確認する

指示の後、AI Agentが出力スキーマを生成しました。

image.png

生成された主な構造は次のとおりです。

{
  "books": [
    {
      "title": "text",
      "price_gbp": "number",
      "availability": "text",
      "rating": "number",
      "product_url": "url",
      "image_url": "url"
    }
  ]
}

価格は数値、評価も数値、商品ページと画像はURL型として定義されました。

各フィールドの説明には、取得に使うCSSセレクタや、星評価のOneからFiveを1から5へ変換する方針も書かれていました。

この段階では手動修正を行わず、そのまま承認しました。

初回実行で20件取得できた

生成されたスクレイパーを実行すると、トップページに表示されていた20冊を取得できました。

最初のレコードは次のような形です。

{
  "title": "A Light in the Attic",
  "price_gbp": 51.77,
  "availability": "In stock",
  "rating": 3,
  "product_url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
  "image_url": "https://books.toscrape.com/media/cache/2c/da/2cdad67c44b002e7ead0cc35693c0e8b.jpg"
}

確認した範囲では、次の条件を満たしていました。

・20件すべて取得
・指定した6項目を出力
・価格から£を除去して数値化
・評価を1から5の数値へ変換
・商品URLと画像URLを絶対URL化

練習用サイトとはいえ、最初の生成で期待した形まで持っていけました。

検証用に試したい場合

専用リンクからBright Dataへ新規登録すると、毎月5,000回分の無料リクエストを利用できます。

Scraper Studioを試してみたい場合は、まずは無料枠の範囲で実際のスクレイピングや動作を確認できます。

肝心の日本語でも動くのか

英語で基本動作を確認できたので、次は日本語で試します。

対象はGIGAZINEです。普段から読んでいるサイトなので、抽出結果も目視で確認しやすいという理由で選びました。

入力した内容は次のとおりです。

現在のトップページに表示されている記事一覧を取得してください。

各記事について、次の項目を抽出してください。

・title: 記事タイトル
・article_url: 記事ページの絶対URL
・published_at: 表示されている公開日時
・category: 表示されているカテゴリ。取得できない場合はnull
・summary: 一覧に表示されている記事概要。取得できない場合はnull
・thumbnail_url: サムネイル画像の絶対URL。取得できない場合はnull

以下の条件を守ってください。

・現在のトップページだけを対象にする
・各記事の詳細ページは開かない
・ページネーションや無限スクロールは行わない
・最大10件まで取得する
・フィールド名は上記の英語名を維持する
・記事本文全文は取得しない
・URLは相対URLではなく絶対URLにする
・指定していないフィールドは追加しない

最初の試行ではInternal Server Error

日本語プロンプトの初回実行でエラー

Internal Server Errorが表示されました。ただし、同じ日本語プロンプトを再実行すると、正常にスキーマ生成まで進みました。

英語版が先に成功したため一瞬日本語を疑いましたが、各条件で一度ずつしか試していません。言語差ではなく、一時的なエラーだった可能性もあります。

image.png

日本語版と英語版ではスキーマに小さな差が出た

日本語版と英語版は、どちらも記事タイトル、URL、公開日時、カテゴリ、サムネイルURLを認識しました。

初期スキーマはほぼ同じでしたが、thumbnail_urlは英語版ではimage、日本語版ではurlとして生成されました。

ただし、各言語で1回ずつ生成した結果なので、言語による差ではなく、生成時の揺れと考えるのが妥当です。

また、最初の生成では両方ともsummaryが抜けていました。

英語版でsummaryを追加するよう再度依頼すると、今度はトップレベルとarticles配列内の両方に同じフィールドが生成されました。

つまり、次のような重複です。

{
  "title": "...",
  "summary": "...",
  "article_url": "...",
  "articles": [
    {
      "title": "...",
      "summary": "...",
      "article_url": "..."
    }
  ]
}

複数記事を返す用途では、トップレベルの単一記事フィールドは不要です。

そこで、トップレベルの重複を削除し、articles配列内だけに残すよう追加で指示しました。

image.png

修正後は、次の構造になりました。

{
  "type": "object",
  "fields": {
    "articles": {
      "type": "array",
      "items": {
        "type": "object",
        "fields": {
          "title": {
            "type": "text"
          },
          "summary": {
            "type": "text"
          },
          "article_url": {
            "type": "url"
          },
          "published_at": {
            "type": "text"
          },
          "category": {
            "type": "text"
          },
          "thumbnail_url": {
            "type": "image"
          }
        }
      }
    }
  }
}

自然言語からスキーマを作れるのは便利ですが、追加修正後も構造を確認したほうがよさそうです。

完成したはずなのに40件取れた

日本語版と英語版の両方を承認し、実行しました。

タイトル、URL、公開日時、カテゴリ、サムネイルURLは問題なく取得できています。

以降のコード確認とSelf-Healingは、英語版で生成したスクレイパーを使っています。

ここで誤算

最大10件と指定したのに、実行結果は40件でした。

40件という結果を見て、記事ごとに詳細ページを開いているのではないかと疑いました。

しかし生成コードを確認すると、トップページを1回読み込み、その中にある記事カード40件を抽出しているだけでした。

生成されたJavaScriptを読む

スクレーパー詳細画面から「コード」を開くと、ホスト型IDEが表示されます。

image.png

インタラクションコードは、かなり短いものでした。

navigate(input.url);
collect(parse());

入力URLへ移動し、パーサーを実行して結果を収集しています。

生成されるコードはJavaScriptベースですが、navigate()collect()は通常のブラウザ標準APIではありません。Bright Dataの実行環境が提供する関数です。

パーサー側では、次のように記事カードを取得していました。

let articles = $('section .card').toArray().map(card => {
  let $card = $(card);

  let title = $card.find('h2 a span').text_sane();
  let article_url = $card.find('h2 a').attr('href');
  let published_at = $card.find('.date-child time a').text_sane();
  let category = $card.find('.catab').text_sane();

  let thumbnail_url =
    $card.find('.thumb img').attr('src') ||
    $card.find('.thumb img').attr('data-src');

  return {
    title: title || null,
    summary: null,
    article_url: article_url ? new URL(article_url) : null,
    published_at: published_at || null,
    category: category || null,
    thumbnail_url: thumbnail_url ? new Image(thumbnail_url) : null
  };
});

return {
  articles: articles
};

section .cardに一致する要素をtoArray()で配列化し、そのすべてをmap()しています。

どこにもslice(0, 10)はありません。

自然言語では「最大10件」と指定していましたが、生成されたコードには件数制限が入っていませんでした。

summaryについても、取得要素が見つからなかったため、コード上では常にnullを返していました。ダウンロードしたJSONではsummaryフィールド自体が省略されていたため、固定スキーマを前提に後段処理を作る場合は実出力まで確認したほうが安全です。

AIに「10件へ直して」と頼む

コードは直接編集できます。

ただ、今回はSelf-Healing機能で直してみました。

入力した指示は次のとおりです。

Limit the output to the first 10 articles only.

Keep the existing fields and selectors unchanged.

Do not add pagination, scrolling, or navigation to individual article pages.

Update the parser code so that no more than 10 article records are returned.

image.png

AIによる修正処理が終わると、変更前と変更後のコードが左右に表示されました。

!

image.png

追加されたのは次の1行です。

}).slice(0, 10);

今回は配列をすべて生成した後に先頭10件へ絞る実装でした。

処理量だけを考えるなら、slice(0, 10)map()より前に入れる方法もあります。ただし、ページ内の40要素程度であれば、今回の目的には十分です。

今回の操作では、AIの提案がまず差分として表示され、承認と保存確認を経て反映されました。

変更前後を確認し、「Accept changes」を押して初めて次へ進みます。

保存前に変更理由を残せる

差分を承認すると、そのまま即時反映されるのではなく、変更内容の説明を入力する画面が出ました。

image.png

今回は次のように記録しました。

取得結果を先頭10件に制限するため

AIによる変更でも、差分確認、承認、コメント、保存という手順を踏めます。

コードを生成して終わりではなく、変更理由まで残せるのは運用時に助かります。

ドラフトと変更履歴がある

IDEにはドラフト変更機能と変更ログもありました。

image.png

今回の検証では、次の状態を確認できました。

・AIが生成したVersion 1
・ユーザーが更新したVersion 2
・未公開のドラフト
・変更したユーザー
・変更日時
・保存時に入力した変更理由

image.png

Gitそのものではありませんが、バージョン、差分、コメント、履歴を確認できます。

AIがコードを直接変更する機能では、何が変わったか分からないまま反映されるのが一番怖いところです。Scraper Studioでは、少なくとも今回触った範囲では、変更内容を人間が確認してから進められました。

承認やキャンセルにはキーボードショートカットも表示されており、Web IDEとして細かい操作性も考えられています。

修正後は10件になった

変更を保存して再実行すると、今度は指定どおり10件だけ取得できました。

確認項目 修正前 修正後
取得件数 40件 10件
詳細ページへの移動 なし なし
取得フィールド 5項目 5項目

Self-Healingで変わったのは件数制限だけ

タイトル、URL、日時、カテゴリ、画像URLはそのまま維持されました。

取得した10件のうち、先頭2件を抜粋すると次のような結果です。

{
  "articles": [
    {
      "title": "TSMC元社員が中国に情報を売ろうとしたとして起訴される",
      "article_url": "https://gigazine.net/news/20260721-taiwan-indicts-ex-tsmc-employee/",
      "published_at": "07月21日13時45分",
      "category": "メモ",
      "thumbnail_url": "https://i.gzn.jp/img/2026/07/21/taiwan-indicts-ex-tsmc-employee/00_m.jpg"
    },
    {
      "title": "Claude Fable 5に匹敵する性能の中華AI「Kimi K3」が人気すぎてGPUが足りなくなり新規サブスク加入を一時停止する事態に、「Anthropicよりマシな対応」という声も",
      "article_url": "https://gigazine.net/news/20260721-kimi-k3-limit/",
      "published_at": "07月21日13時39分",
      "category": "AI",
      "thumbnail_url": "https://i.gzn.jp/img/2026/07/21/kimi-k3-limit/00_m.png"
    }
  ]
}

10件への制限以外は維持されており、タイトル、URL、日時、カテゴリ、画像URLも取得できています。

JSON以外にも出力できる

実行結果は、今回確認した範囲で次の形式からダウンロードできました。

・JSON
・NDJSON
・CSV
・XLSX

JSONとNDJSONは、APIや後段の処理へ渡しやすい形です。

CSV・XLSXは自動で10行にはならなかった

今回のようにトップレベルへarticles配列を置くと、1回の実行結果が1行となり、articles列には配列全体がJSON文字列として格納されました。

列は次のような構成でした。

articles
input_url
warning
warning_code
error
error_code

Excelで記事一覧として扱う場合は、出力スキーマをフラットにするか、ダウンロード後にarticles配列を展開する必要があります。

スクレイピング時に確認したいこと

Scraper Studioが取得処理を自動化しても、そのデータを取得、保存、再利用してよいかの判断まで自動化されるわけではありません。

利用前には、対象サイトの利用規約、robots.txt、著作権、個人情報の有無、アクセス頻度を確認する必要があります。

今回の検証では公開ページのみを対象にし、詳細ページへの移動、ページネーション、無限スクロールを行わず、検証に必要な範囲へ限定しました。

APIとスケジュール実行にもつなげられる

作成したスクレイパーは、管理画面から手動実行するだけではありません。

「APIで開始する」画面では、入力値やキューの扱いを設定すると、認証付きのAPIコードがその場で表示されます。

APIコードを画面上で確認できる

今回はPythonを選択しました。

生成されたコードでは、POST /dca/triggerへCollector IDと入力URLを送り、バッチ収集を開始する構成になっていました。

実行直後にはジョブのIDが返され、そのIDを使って/dca/datasetから結果を取得します。コード内の認証情報はAPI_TOKENというプレースホルダーになっており、実際のトークンを記事へ載せずに済みます。

言語名のプルダウンもあり、用途に合わせて別言語のサンプルへ切り替えられます。

出力形式と配信先も指定できる

同じ画面の「Custom delivery settings」を開くと、出力形式と配信方法を指定できました。

形式は次の4種類です。

種類 対応形式
出力形式 JSON / NDJSON / CSV / XLSX
API APIダウンロード
オブジェクトストレージ Amazon S3 / Google Cloud Storage / Microsoft Azure Storage / Alibaba Cloud OSS
その他の配信先 SFTP / Google Cloud Pub/Sub

結果は手動ダウンロードだけでなく、既存のストレージやデータ処理基盤へ直接渡せます。

image.png

PyCharmから実際にAPIを実行する

画面に表示されたPython例を土台に、環境変数の読み込みと結果取得までのポーリング処理を追加しました。

APIトークンとCollector IDは環境変数から読み込んでいます。

検証に使ったPythonコード
import os
import time
import requests
from dotenv import load_dotenv

load_dotenv()

API_TOKEN = os.environ["BRIGHT_DATA_API_TOKEN"]
COLLECTOR_ID = os.environ["BRIGHT_DATA_COLLECTOR_ID"]

url = "https://api.brightdata.com/dca/trigger"
headers = {
	"Authorization": f"Bearer {API_TOKEN}",
	"Content-Type": "application/json",
}
params = {
	"collector": COLLECTOR_ID,
	"queue_next": "1",
}
data = [
	{"url":"https://gigazine.net/"},
]

response = requests.post(url, headers=headers, params=params, json=data)
resp_json = response.json()
if not response.ok:
	raise Exception(resp_json["message"])
if not "collection_id" in resp_json:
	raise Exception("No collection_id in response")
print(f"start > id: {resp_json['collection_id']}")

url = "https://api.brightdata.com/dca/dataset"
params = {
	"id": resp_json["collection_id"],
}

old_msg = ""
while True:
    response = requests.get(url, headers=headers, params=params)
    if response.ok:
        if not "status" in response.json():
            result = response.json()
            break
        if not response.json()["status"] in ["collecting", "building"]:
            raise Exception("Unexpected status")
        if old_msg != response.json()["status"]:
            old_msg = response.json()["status"]
            print(f'{response.json()["status"]} > {response.json()["message"]}')
    else:
        print("Error. Retrying in 5 seconds...")
    time.sleep(5)  # Wait for 5 seconds before the next request
print(result)

実行すると、最初にcollection_idが返されました。

その後、状態がcollectingbuildingと変化し、準備が完了すると10件の記事データを含むJSONを取得できました。

start > id: j_...
collecting > Job is not finished
building > Dataset is not ready yet, try again in 30s
[{"articles": [...10件...], "input": {"url": "https://gigazine.net/"}}]

プロセスは終了コード 0 で終了しました

image.png

API経由でも10件取得できた

PyCharmからCollectorを起動し、collectingbuildingを経て、Self-Healing後の10件を取得できました。

今回のコードは動作確認用の簡易実装です。継続運用する場合は、HTTPタイムアウト、最大待機時間、再試行回数、バックオフ処理を追加したほうが安全です。

定期実行はWeb画面から設定できる

「サブスクリプション」では、開始日時、タイムゾーン、繰り返し間隔、曜日、終了条件を画面上から設定できます。

image.png

さらに、スクレイパーごとに1分あたりのセッション開始数を制限するレートリミットも設定できました。

image.png

APIや定期実行を使う場合、短時間に処理が集中しないよう上限を設けられます。ただし、レートリミットを設定すれば利用規約やアクセス負荷の確認が不要になるわけではありません。

GIGAZINE用スクレイパーで考えられる運用例

・毎日決まった時刻にトップページを取得する
・その日のカテゴリ別記事数を集計する
・AIカテゴリの記事だけを保存する
・前日との差分を記録する
・月末に1か月分の傾向をまとめる

スクレイパーを生成した後、別の実行環境やcronを最初から用意しなくても、API実行、定期収集、外部ストレージへの配信へ進めます。

今回は画面上のAPIコードと配信先を確認したうえで、PyCharmから実際にCollectorを起動し、10件の結果を取得しました。スケジュールとレートリミットは設定画面まで確認しています。外部ストレージへの実配信と、継続的なスケジュール運用までは行っていません。

実際に使って分かったこと

良かったところ

生成されたコードを自分で読める

AI生成サービスの中には、裏で何をしているか分からないものもあります。Scraper StudioではJavaScriptコードを開き、CSSセレクタやデータ変換を確認できました。

自然言語で修正して、差分を見てから反映できる

「10件へ制限して」と頼むだけでコードを修正できました。変更前後を比較し、承認するまで反映されないため、AI修正をそのまま信じる必要はありません。

作成後の運用機能まで同じ画面にある

API、スケジュール、出力、変更履歴が同じスクレイパーにまとまっています。コードだけ生成するAIとは違い、定期収集までつなげやすい構成でした。

UIの多くが日本語化されている

スキーマ確認、実行、コード編集、変更ログなど、主要な操作は日本語UIで進められました。一部の説明やボタンは英語のままですが、操作に迷う場面は多くありませんでした。

気になったところ

自然言語の条件が必ずコードへ入るとは限らない

今回の「最大10件」は、最初の生成コードには反映されませんでした。件数、ページネーション、詳細ページへの移動など、費用や負荷に関係する条件はコードと実行結果の確認が必要です。

追加指示でスキーマが重複した

summaryの追加時に、トップレベルと配列内へ同じフィールドが生成されました。修正はできましたが、追加変更後も構造を確認したほうがよさそうです。

一時的なInternal Server Errorが出た

日本語の初回試行ではエラーが出ました。同じ指示の再実行では成功したため、言語が原因とは断定できません。

CSVとXLSXはネストした配列を自動展開しない

表計算ソフトで直接扱うことを想定している場合は、出力構造を考える必要があります。

どんな人に向いているか

向いていそうな人

・新しい対象サイトへ短時間で対応したい
・生成コードは自分でも確認、修正したい
・実行基盤や定期実行を別途組む手間を減らしたい
・自然言語でたたき台を作り、最後は自分で調整したい
・複数のスクレイパーを履歴付きで管理したい

完全に任せきりにはしないほうがいい

今回も、初回生成だけでは件数条件が反映されませんでした。完全なノーコードというより、AIに初期実装を任せ、必要な部分を開発者が引き継ぐ環境として見るのが近いと思います。

まとめ

URLと自然言語から、Books to ScrapeとGIGAZINE用のスクレイパーを作成できました。

Books to Scrapeでは、手修正なしで20冊分のデータを取得できました。

GIGAZINEでも日本語の指示からスキーマを生成し、タイトル、URL、公開日時、カテゴリ、サムネイルを取得できました。

一方で、「最大10件」という条件は初回コードに反映されず、40件取得されました。

その後、生成されたJavaScriptをIDEで確認し、Self-Healingへ修正を依頼しました。差分を確認してから承認し、変更理由を履歴へ残したうえで、最終的に10件へ制限できました。

実際に触ってみて便利だと感じたのは、最初のAI生成だけではありません。

生成後のコード確認、自然言語による修正、差分レビュー、ドラフト、バージョン履歴、API、スケジュールまで、同じスクレイパーの流れとして扱える点です。

初回生成をそのまま本番へ流すのではなく、コードと実行結果の確認は必要です。

それでも、セレクタ調査からAPI実行、定期処理までを毎回ゼロから組んでいる人なら、かなり手間を減らせそうです。

Bright Dataを無料で試す方法

今回使用したScraper Studioは、こちらの専用リンクからBright Dataへ新規登録できます。

専用リンクから登録すると、毎月5,000回分の無料リクエストを利用できます。

まずは無料枠を使って、この記事で紹介したScraper Studioの作成やスクレイピングを実際に試してみることができます。

登録後は、次の手順でScraper Studioを利用できます。

  1. 専用リンクからBright Dataへアクセスする
  2. アカウントを新規登録してログインする
  3. Bright DataのダッシュボードからScraper Studioを開く
  4. 新しいスクレーパーを作成する
  5. 対象サイトや取得したいデータを設定して実行する

無料枠について

専用リンクから新規登録すると、毎月5,000回分の無料リクエストを利用できます。

クレジットカードなしで始められるため、「まずScraper Studioがどんなものか試してみたい」という場合にも利用しやすいです。

肝心の日本語でも動くのか

英語で基本動作を確認できたので、次は日本語で試します。

対象はGIGAZINEです。普段から読んでいるサイトなので、抽出結果も目視で確認しやすいという理由で選びました。

入力した内容は次のとおりです。

現在のトップページに表示されている記事一覧を取得してください。

各記事について、次の項目を抽出してください。

・title: 記事タイトル
・article_url: 記事ページの絶対URL
・published_at: 表示されている公開日時
・category: 表示されているカテゴリ。取得できない場合はnull
・summary: 一覧に表示されている記事概要。取得できない場合はnull
・thumbnail_url: サムネイル画像の絶対URL。取得できない場合はnull

以下の条件を守ってください。

・現在のトップページだけを対象にする
・各記事の詳細ページは開かない
・ページネーションや無限スクロールは行わない
・最大10件まで取得する
・フィールド名は上記の英語名を維持する
・記事本文全文は取得しない
・URLは相対URLではなく絶対URLにする
・指定していないフィールドは追加しない

最初の試行ではInternal Server Error

日本語プロンプトの初回実行でエラー

Internal Server Errorが表示されました。ただし、同じ日本語プロンプトを再実行すると、正常にスキーマ生成まで進みました。

英語版が先に成功したため一瞬日本語を疑いましたが、各条件で一度ずつしか試していません。言語差ではなく、一時的なエラーだった可能性もあります。

image.png

日本語版と英語版ではスキーマに小さな差が出た

日本語版と英語版は、どちらも記事タイトル、URL、公開日時、カテゴリ、サムネイルURLを認識しました。

初期スキーマはほぼ同じでしたが、thumbnail_urlは英語版ではimage、日本語版ではurlとして生成されました。

ただし、各言語で1回ずつ生成した結果なので、言語による差ではなく、生成時の揺れと考えるのが妥当です。

また、最初の生成では両方ともsummaryが抜けていました。

英語版でsummaryを追加するよう再度依頼すると、今度はトップレベルとarticles配列内の両方に同じフィールドが生成されました。

つまり、次のような重複です。

{
  "title": "...",
  "summary": "...",
  "article_url": "...",
  "articles": [
    {
      "title": "...",
      "summary": "...",
      "article_url": "..."
    }
  ]
}

複数記事を返す用途では、トップレベルの単一記事フィールドは不要です。

そこで、トップレベルの重複を削除し、articles配列内だけに残すよう追加で指示しました。

image.png

修正後は、次の構造になりました。

{
  "type": "object",
  "fields": {
    "articles": {
      "type": "array",
      "items": {
        "type": "object",
        "fields": {
          "title": {
            "type": "text"
          },
          "summary": {
            "type": "text"
          },
          "article_url": {
            "type": "url"
          },
          "published_at": {
            "type": "text"
          },
          "category": {
            "type": "text"
          },
          "thumbnail_url": {
            "type": "image"
          }
        }
      }
    }
  }
}

自然言語からスキーマを作れるのは便利ですが、追加修正後も構造を確認したほうがよさそうです。

完成したはずなのに40件取れた

日本語版と英語版の両方を承認し、実行しました。

タイトル、URL、公開日時、カテゴリ、サムネイルURLは問題なく取得できています。

以降のコード確認とSelf-Healingは、英語版で生成したスクレイパーを使っています。

ここで誤算

最大10件と指定したのに、実行結果は40件でした。

40件という結果を見て、記事ごとに詳細ページを開いているのではないかと疑いました。

しかし生成コードを確認すると、トップページを1回読み込み、その中にある記事カード40件を抽出しているだけでした。

生成されたJavaScriptを読む

スクレーパー詳細画面から「コード」を開くと、ホスト型IDEが表示されます。

image.png

インタラクションコードは、かなり短いものでした。

navigate(input.url);
collect(parse());

入力URLへ移動し、パーサーを実行して結果を収集しています。

生成されるコードはJavaScriptベースですが、navigate()collect()は通常のブラウザ標準APIではありません。Bright Dataの実行環境が提供する関数です。

パーサー側では、次のように記事カードを取得していました。

let articles = $('section .card').toArray().map(card => {
  let $card = $(card);

  let title = $card.find('h2 a span').text_sane();
  let article_url = $card.find('h2 a').attr('href');
  let published_at = $card.find('.date-child time a').text_sane();
  let category = $card.find('.catab').text_sane();

  let thumbnail_url =
    $card.find('.thumb img').attr('src') ||
    $card.find('.thumb img').attr('data-src');

  return {
    title: title || null,
    summary: null,
    article_url: article_url ? new URL(article_url) : null,
    published_at: published_at || null,
    category: category || null,
    thumbnail_url: thumbnail_url ? new Image(thumbnail_url) : null
  };
});

return {
  articles: articles
};

section .cardに一致する要素をtoArray()で配列化し、そのすべてをmap()しています。

どこにもslice(0, 10)はありません。

自然言語では「最大10件」と指定していましたが、生成されたコードには件数制限が入っていませんでした。

summaryについても、取得要素が見つからなかったため、コード上では常にnullを返していました。ダウンロードしたJSONではsummaryフィールド自体が省略されていたため、固定スキーマを前提に後段処理を作る場合は実出力まで確認したほうが安全です。

AIに「10件へ直して」と頼む

コードは直接編集できます。

ただ、今回はSelf-Healing機能で直してみました。

入力した指示は次のとおりです。

Limit the output to the first 10 articles only.

Keep the existing fields and selectors unchanged.

Do not add pagination, scrolling, or navigation to individual article pages.

Update the parser code so that no more than 10 article records are returned.

image.png

AIによる修正処理が終わると、変更前と変更後のコードが左右に表示されました。

!

image.png

追加されたのは次の1行です。

}).slice(0, 10);

今回は配列をすべて生成した後に先頭10件へ絞る実装でした。

処理量だけを考えるなら、slice(0, 10)map()より前に入れる方法もあります。ただし、ページ内の40要素程度であれば、今回の目的には十分です。

今回の操作では、AIの提案がまず差分として表示され、承認と保存確認を経て反映されました。

変更前後を確認し、「Accept changes」を押して初めて次へ進みます。

保存前に変更理由を残せる

差分を承認すると、そのまま即時反映されるのではなく、変更内容の説明を入力する画面が出ました。

image.png

今回は次のように記録しました。

取得結果を先頭10件に制限するため

AIによる変更でも、差分確認、承認、コメント、保存という手順を踏めます。

コードを生成して終わりではなく、変更理由まで残せるのは運用時に助かります。

ドラフトと変更履歴がある

IDEにはドラフト変更機能と変更ログもありました。

image.png

今回の検証では、次の状態を確認できました。

・AIが生成したVersion 1
・ユーザーが更新したVersion 2
・未公開のドラフト
・変更したユーザー
・変更日時
・保存時に入力した変更理由

image.png

Gitそのものではありませんが、バージョン、差分、コメント、履歴を確認できます。

AIがコードを直接変更する機能では、何が変わったか分からないまま反映されるのが一番怖いところです。Scraper Studioでは、少なくとも今回触った範囲では、変更内容を人間が確認してから進められました。

承認やキャンセルにはキーボードショートカットも表示されており、Web IDEとして細かい操作性も考えられています。

修正後は10件になった

変更を保存して再実行すると、今度は指定どおり10件だけ取得できました。

確認項目 修正前 修正後
取得件数 40件 10件
詳細ページへの移動 なし なし
取得フィールド 5項目 5項目

Self-Healingで変わったのは件数制限だけ

タイトル、URL、日時、カテゴリ、画像URLはそのまま維持されました。

取得した10件のうち、先頭2件を抜粋すると次のような結果です。

{
  "articles": [
    {
      "title": "TSMC元社員が中国に情報を売ろうとしたとして起訴される",
      "article_url": "https://gigazine.net/news/20260721-taiwan-indicts-ex-tsmc-employee/",
      "published_at": "07月21日13時45分",
      "category": "メモ",
      "thumbnail_url": "https://i.gzn.jp/img/2026/07/21/taiwan-indicts-ex-tsmc-employee/00_m.jpg"
    },
    {
      "title": "Claude Fable 5に匹敵する性能の中華AI「Kimi K3」が人気すぎてGPUが足りなくなり新規サブスク加入を一時停止する事態に、「Anthropicよりマシな対応」という声も",
      "article_url": "https://gigazine.net/news/20260721-kimi-k3-limit/",
      "published_at": "07月21日13時39分",
      "category": "AI",
      "thumbnail_url": "https://i.gzn.jp/img/2026/07/21/kimi-k3-limit/00_m.png"
    }
  ]
}

10件への制限以外は維持されており、タイトル、URL、日時、カテゴリ、画像URLも取得できています。

JSON以外にも出力できる

実行結果は、今回確認した範囲で次の形式からダウンロードできました。

・JSON
・NDJSON
・CSV
・XLSX

JSONとNDJSONは、APIや後段の処理へ渡しやすい形です。

CSV・XLSXは自動で10行にはならなかった

今回のようにトップレベルへarticles配列を置くと、1回の実行結果が1行となり、articles列には配列全体がJSON文字列として格納されました。

列は次のような構成でした。

articles
input_url
warning
warning_code
error
error_code

Excelで記事一覧として扱う場合は、出力スキーマをフラットにするか、ダウンロード後にarticles配列を展開する必要があります。

スクレイピング時に確認したいこと

Scraper Studioが取得処理を自動化しても、そのデータを取得、保存、再利用してよいかの判断まで自動化されるわけではありません。

利用前には、対象サイトの利用規約、robots.txt、著作権、個人情報の有無、アクセス頻度を確認する必要があります。

今回の検証では公開ページのみを対象にし、詳細ページへの移動、ページネーション、無限スクロールを行わず、検証に必要な範囲へ限定しました。

APIとスケジュール実行にもつなげられる

作成したスクレイパーは、管理画面から手動実行するだけではありません。

「APIで開始する」画面では、入力値やキューの扱いを設定すると、認証付きのAPIコードがその場で表示されます。

APIコードを画面上で確認できる

今回はPythonを選択しました。

生成されたコードでは、POST /dca/triggerへCollector IDと入力URLを送り、バッチ収集を開始する構成になっていました。

実行直後にはジョブのIDが返され、そのIDを使って/dca/datasetから結果を取得します。コード内の認証情報はAPI_TOKENというプレースホルダーになっており、実際のトークンを記事へ載せずに済みます。

言語名のプルダウンもあり、用途に合わせて別言語のサンプルへ切り替えられます。

出力形式と配信先も指定できる

同じ画面の「Custom delivery settings」を開くと、出力形式と配信方法を指定できました。

形式は次の4種類です。

種類 対応形式
出力形式 JSON / NDJSON / CSV / XLSX
API APIダウンロード
オブジェクトストレージ Amazon S3 / Google Cloud Storage / Microsoft Azure Storage / Alibaba Cloud OSS
その他の配信先 SFTP / Google Cloud Pub/Sub

結果は手動ダウンロードだけでなく、既存のストレージやデータ処理基盤へ直接渡せます。

image.png

PyCharmから実際にAPIを実行する

画面に表示されたPython例を土台に、環境変数の読み込みと結果取得までのポーリング処理を追加しました。

APIトークンとCollector IDは環境変数から読み込んでいます。

検証に使ったPythonコード
import os
import time
import requests
from dotenv import load_dotenv

load_dotenv()

API_TOKEN = os.environ["BRIGHT_DATA_API_TOKEN"]
COLLECTOR_ID = os.environ["BRIGHT_DATA_COLLECTOR_ID"]

url = "https://api.brightdata.com/dca/trigger"
headers = {
	"Authorization": f"Bearer {API_TOKEN}",
	"Content-Type": "application/json",
}
params = {
	"collector": COLLECTOR_ID,
	"queue_next": "1",
}
data = [
	{"url":"https://gigazine.net/"},
]

response = requests.post(url, headers=headers, params=params, json=data)
resp_json = response.json()
if not response.ok:
	raise Exception(resp_json["message"])
if not "collection_id" in resp_json:
	raise Exception("No collection_id in response")
print(f"start > id: {resp_json['collection_id']}")

url = "https://api.brightdata.com/dca/dataset"
params = {
	"id": resp_json["collection_id"],
}

old_msg = ""
while True:
    response = requests.get(url, headers=headers, params=params)
    if response.ok:
        if not "status" in response.json():
            result = response.json()
            break
        if not response.json()["status"] in ["collecting", "building"]:
            raise Exception("Unexpected status")
        if old_msg != response.json()["status"]:
            old_msg = response.json()["status"]
            print(f'{response.json()["status"]} > {response.json()["message"]}')
    else:
        print("Error. Retrying in 5 seconds...")
    time.sleep(5)  # Wait for 5 seconds before the next request
print(result)

実行すると、最初にcollection_idが返されました。

その後、状態がcollectingbuildingと変化し、準備が完了すると10件の記事データを含むJSONを取得できました。

start > id: j_...
collecting > Job is not finished
building > Dataset is not ready yet, try again in 30s
[{"articles": [...10件...], "input": {"url": "https://gigazine.net/"}}]

プロセスは終了コード 0 で終了しました

image.png

API経由でも10件取得できた

PyCharmからCollectorを起動し、collectingbuildingを経て、Self-Healing後の10件を取得できました。

今回のコードは動作確認用の簡易実装です。継続運用する場合は、HTTPタイムアウト、最大待機時間、再試行回数、バックオフ処理を追加したほうが安全です。

定期実行はWeb画面から設定できる

「サブスクリプション」では、開始日時、タイムゾーン、繰り返し間隔、曜日、終了条件を画面上から設定できます。

image.png

さらに、スクレイパーごとに1分あたりのセッション開始数を制限するレートリミットも設定できました。

image.png

APIや定期実行を使う場合、短時間に処理が集中しないよう上限を設けられます。ただし、レートリミットを設定すれば利用規約やアクセス負荷の確認が不要になるわけではありません。

GIGAZINE用スクレイパーで考えられる運用例

・毎日決まった時刻にトップページを取得する
・その日のカテゴリ別記事数を集計する
・AIカテゴリの記事だけを保存する
・前日との差分を記録する
・月末に1か月分の傾向をまとめる

スクレイパーを生成した後、別の実行環境やcronを最初から用意しなくても、API実行、定期収集、外部ストレージへの配信へ進めます。

今回は画面上のAPIコードと配信先を確認したうえで、PyCharmから実際にCollectorを起動し、10件の結果を取得しました。スケジュールとレートリミットは設定画面まで確認しています。外部ストレージへの実配信と、継続的なスケジュール運用までは行っていません。

実際に使って分かったこと

良かったところ

生成されたコードを自分で読める

AI生成サービスの中には、裏で何をしているか分からないものもあります。Scraper StudioではJavaScriptコードを開き、CSSセレクタやデータ変換を確認できました。

自然言語で修正して、差分を見てから反映できる

「10件へ制限して」と頼むだけでコードを修正できました。変更前後を比較し、承認するまで反映されないため、AI修正をそのまま信じる必要はありません。

作成後の運用機能まで同じ画面にある

API、スケジュール、出力、変更履歴が同じスクレイパーにまとまっています。コードだけ生成するAIとは違い、定期収集までつなげやすい構成でした。

UIの多くが日本語化されている

スキーマ確認、実行、コード編集、変更ログなど、主要な操作は日本語UIで進められました。一部の説明やボタンは英語のままですが、操作に迷う場面は多くありませんでした。

気になったところ

自然言語の条件が必ずコードへ入るとは限らない

今回の「最大10件」は、最初の生成コードには反映されませんでした。件数、ページネーション、詳細ページへの移動など、費用や負荷に関係する条件はコードと実行結果の確認が必要です。

追加指示でスキーマが重複した

summaryの追加時に、トップレベルと配列内へ同じフィールドが生成されました。修正はできましたが、追加変更後も構造を確認したほうがよさそうです。

一時的なInternal Server Errorが出た

日本語の初回試行ではエラーが出ました。同じ指示の再実行では成功したため、言語が原因とは断定できません。

CSVとXLSXはネストした配列を自動展開しない

表計算ソフトで直接扱うことを想定している場合は、出力構造を考える必要があります。

どんな人に向いているか

向いていそうな人

・新しい対象サイトへ短時間で対応したい
・生成コードは自分でも確認、修正したい
・実行基盤や定期実行を別途組む手間を減らしたい
・自然言語でたたき台を作り、最後は自分で調整したい
・複数のスクレイパーを履歴付きで管理したい

完全に任せきりにはしないほうがいい

今回も、初回生成だけでは件数条件が反映されませんでした。完全なノーコードというより、AIに初期実装を任せ、必要な部分を開発者が引き継ぐ環境として見るのが近いと思います。

まとめ

URLと自然言語から、Books to ScrapeとGIGAZINE用のスクレイパーを作成できました。

Books to Scrapeでは、手修正なしで20冊分のデータを取得できました。

GIGAZINEでも日本語の指示からスキーマを生成し、タイトル、URL、公開日時、カテゴリ、サムネイルを取得できました。

一方で、「最大10件」という条件は初回コードに反映されず、40件取得されました。

その後、生成されたJavaScriptをIDEで確認し、Self-Healingへ修正を依頼しました。差分を確認してから承認し、変更理由を履歴へ残したうえで、最終的に10件へ制限できました。

実際に触ってみて便利だと感じたのは、最初のAI生成だけではありません。

生成後のコード確認、自然言語による修正、差分レビュー、ドラフト、バージョン履歴、API、スケジュールまで、同じスクレイパーの流れとして扱える点です。

初回生成をそのまま本番へ流すのではなく、コードと実行結果の確認は必要です。

それでも、セレクタ調査からAPI実行、定期処理までを毎回ゼロから組んでいる人なら、かなり手間を減らせそうです。

Bright Dataを無料で試す方法

今回使用したScraper Studioは、こちらの専用リンクからBright Dataへ新規登録できます。

専用リンクから登録すると、毎月5,000回分の無料リクエストを利用できます。

まずは無料枠を使って、この記事で紹介したScraper Studioの作成やスクレイピングを実際に試してみることができます。

登録後は、次の手順でScraper Studioを利用できます。

  1. 専用リンクからBright Dataへアクセスする
  2. アカウントを新規登録してログインする
  3. Bright DataのダッシュボードからScraper Studioを開く
  4. 新しいスクレーパーを作成する
  5. 対象サイトや取得したいデータを設定して実行する

無料枠について

専用リンクから新規登録すると、毎月5,000回分の無料リクエストを利用できます。

クレジットカードなしで始められるため、「まずScraper Studioがどんなものか試してみたい」という場合にも利用しやすいです。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?