🎯 カスタマイズ可能で検出回避型のクラウドブラウザ。自社開発のChromiumを搭載し、ウェブクローラーAIエージェント向けに設計されています。👉今すぐ試す
ブログに戻ります

ScrapeGraphAI + Scrapeless: CloudブラウザにSmartScraperGraphをポイントする

Emily Chen
Emily Chen

Advanced Data Extraction Specialist

07-Aug-2026

TL;DR:

  • ScrapeGraphAIは、セレクタの代わりにプロンプトを使用して抽出しますが、下層のフェッチは、あなた自身のマシンで起動された普通のPlaywrightブラウザです。
  • pip install scrapegraphaiは、Playwrightクライアントを提供し、ブラウザバイナリを提供しないため、ストックローダーは新しいインストール時にplaywright install chromiumを実行するまで失敗します。
  • ChromiumLoadergetattr(self, f"ascrape_{self.backend}")を使ってフェッチメソッドを選択するため、backendは固定リストから選ぶのではなくメソッドの名前を指定します — これがカスタムフェッチバックエンドが依存する部分です。
  • 短いサブクラスのascrape_scrapelessメソッドは、wss:// CDP接続を介してScrapeless Scraping Browserを通じてフェッチし、ローカルにブラウザをインストールする必要はありません。
  • FetchNodeChromiumLoaderを名前でインポートするため、fetch_node.ChromiumLoaderを再バインドすることが実際にグラフがあなたのサブクラスを使用する原因です。それをスキップすると、正しく見えるローダーは静かに無視されます。
  • パイプライン全体はローカルモデルで実行されます: SmartScraperGraphollama/qwen2.5:0.5bとともに構造化された著者と引用のペアを返し、クラウドモデルキーは不要です。
  • Scrapeless無料プランから始めて、フェッチをあなたのラップトップから移動させてください。

Scrapeless Scraping Browserは、立ち上げるのではなく接続するクラウドブラウザです。これは、安全なWebSocket CDPエンドポイントでリッスンしており、ScrapeGraphAIのフェッチレイヤーが裏でPlaywrightを利用しているため、Playwrightが自身が起動していないブラウザに接続できるという点で重要です。

ScrapeGraphAIは、人々が話すパイプラインの一部です: 望むことを文で説明すると、ノードのグラフがページを構造化されたJSONに変換します, CSSセレクタは一切使用しません。誰も話さない部分は最初のノードです。どのモデルも何かを見る前に、FetchNodeはHTMLを生成しなければならず、それを行うためにスクリプトが実行されている任意のマシンでChromiumを起動します。検索結果の最初のページにあるすべてのチュートリアルは、そのノードをまったく同じ方法で構成し、プロキシ辞書を使用し、そこで停止します。

このガイドはフェッチレイヤーに焦点を当てています: それがどこに存在し、実際の拡張ポイントは何であり、クラウドブラウザを介してそれをルーティングする方法です。以下のすべてのブロックは、ライブで実行され、抽出を含みます。

Where ScrapeGraphAI's Fetch Layer Actually Lives

FetchNodeはほぼすべてのグラフのエントリノードであり、いくつかの分岐の1つで終了します。ノード設定でbrowser_basescrape_do、またはplasmateを設定した場合、scrapegraphai/docloaders/内のベンダーローダーに渡されます。そうでない場合は、デフォルトパスであるChromiumLoaderに落ち着き、ほとんど全員が使用している道です。

そのフォールバックは二つの理由から重要です。ベンダーのフェッチバックエンドは、これを発明しているのではなく、すでにこのコードベースで確立された形状を持っています — browser_base.pyscrape_do.pyはレポに同梱されています。ChromiumLoaderは自分自身のフェッチメソッドを名前で選択します:

python Copy
scraping_fn = getattr(self, f"ascrape_{self.backend}")

backendは固定列挙体に対して検証されません。それは属性ルックアップへの文字列補間であるため、ascrape_<something>と呼ばれる任意のメソッドは、backend<something>に設定することによって到達可能になります。それがそのつなぎ目です。

デフォルトのascrape_playwrightp.chromium.launch(...)を呼び出し、ローカルでブラウザプロセスを開始します。それをすでに実行中のブラウザへのWebSocket接続に交換するのは、一つの呼び出しの変更です。

Prerequisites

  • Python 3.10以上。
  • ダッシュボードからのScrapeless APIキー、SCRAPELESS_KEYとしてエクスポート。
  • クラウドモデルキーが不要で、抽出ステップを追う場合には、ローカルで実行中のOllamaとプルされたモデル。
  • クラウドパスではローカルブラウザバイナリは必要ありません。ストックローダーを実行したい場合にのみ必要です。

Install

bash Copy
pip install "scrapegraphai==2.1.6" "langchain-ollama==1.1.0"

Playwrightは依存関係として到着しますが、そのブラウザは到着しません。この区別が、ほとんどの人が直面する最初の失敗を引き起こします。

bash Copy
export SCRAPELESS_KEY="your_api_key_here"

What a Fresh Install Actually Fetches

ストックローダーをインストール直後に実行すると、ページには全く到達しません。

python Copy
from scrapegraphai.docloaders import ChromiumLoader

try:
    docs = ChromiumLoader(["https://quotes.toscrape.com/"], headless=True).load()
    print("chars:", len(docs[0].page_content))
except Exception as exc:
    print(f"{type(exc).__name__}: {str(exc).split(' at /')[0]}")
text Copy
RuntimeError: Failed to scrape after 1 attempts: BrowserType.launch: Executable doesn't exist

Playwrightクライアントはインストールされています; 起動したいChromiumはインストールされていません。playwright install chromiumがそれを修正し、グラフを実行するすべてのマシンに数百メガバイトのコストがかかります — CIイメージ、コンテナ、各開発者のラップトップ。クラウドパスではそれを完全にスキップします; なぜなら、彼女が駆動するブラウザはすでに他のどこかで実行中だからです。

Point the Loader at a Cloud Browser

ChromiumLoaderをサブクラス化し、希望するバックエンドの名前を付けたメソッドを追加し、super().__init__が実行された後にself.backendを再バインドします。

python Copy
import os

from scrapegraphai.docloaders import ChromiumLoader

CDP = (
    "wss://browser.scrapeless.com/api/v2/browser"
    f"?token={os.environ['SCRAPELESS_KEY']}&sessionTTL=180&proxyCountry=ANY"
)


class ScrapelessLoader(ChromiumLoader):
    """Fetch through a remote CDP browser instead of launching one locally."""

    def __init__(self, urls, **kwargs):
        kwargs.pop("backend", None)
        super().__init__(urls, backend="playwright", **kwargs)
        self.backend = "scrapeless"

    async def ascrape_scrapeless(self, url: str, browser_name: str = "chromium") -> str:
        from playwright.async_api import async_playwright

        async with async_playwright() as p:
            browser = await p.chromium.connect_over_cdp(CDP)
            page = await browser.new_page()
            await page.goto(url, wait_until=self.load_state)
            html = await page.content()
            await browser.close()
            return html


loader = ScrapelessLoader(["https://quotes.toscrape.com/"])
print("dispatches to:", getattr(loader, f"ascrape_{loader.backend}").__name__)
docs = loader.load()
print("chars:", len(docs[0].page_content))
print("Einstein present:", "Einstein" in docs[0].page_content)

二つの詳細が作業を行います。super().__init__backend="playwright" で呼び出されます。なぜなら、コンストラクターがその文字列に対してインポートチェックを実行するからです。playwright は解決される名前です; self.backend は再割り当てされ、その後 lazy_load でディスパッチが ascrape_scrapeless を見つけます。browser_name をデフォルト付きでシグネチャに保持してください — ディスパッチャはそのメソッドを URL のみで呼び出します。

text Copy
dispatches to: ascrape_scrapeless
chars: 10968
Einstein present: True

ページは、このマシンに存在しなかったブラウザから完全にレンダリングされた状態で返されます。proxyCountry は、特定の国からリクエストをエグレスする必要がある場合は二文字のコードを受け入れ、sessionTTL はリモートセッションが開いている時間の長さを制限します。

グラフを利用する

サブクラスを自分でインスタンス化することで取得が機能することが証明されますが、グラフは自力ではそれを認識しません。FetchNodefrom ..docloaders import ChromiumLoader を実行し、その後その名前を直接呼び出すので、グラフが使用するクラスはノードのモジュールネームスペースでバインドされるものです。グラフを構築する前に再バインドしてください。

python Copy
import scrapegraphai.nodes.fetch_node as fetch_node

fetch_node.ChromiumLoader = ScrapelessLoader

これは、上記のいずれかが効果を持つかどうかを決定するステップです。正しく書かれたサブクラスですが、決してバインドされないものは、実行され、成功し、ローカルブラウザを通じて静かに全体を取得するグラフを生成します。

置き換えが同じコンストラクターシグネチャを維持するため、FetchNode が既に通過するすべてのもの — headlessstorage_state、および loader_kwargs に入れたもの — はそのまま到着し続けます。

自分のマシンから取得を移動する準備はできていますか? 無料のScrapelessアカウントを作成する そして最初のグラフをそれに指し示してください。

ローカルモデルで全体のグラフを実行する

ローダーがバインドされると、SmartScraperGraph は通常どおりに動作します。llm ブロックをOllamaに指し示すことで、全体のパイプラインが有料APIから外れ、取得レイヤーの反復が安価になります。

python Copy
import os

import scrapegraphai.nodes.fetch_node as fetch_node
from scrapegraphai.docloaders import ChromiumLoader
from scrapegraphai.graphs import SmartScraperGraph

CDP = (
    "wss://browser.scrapeless.com/api/v2/browser"
    f"?token={os.environ['SCRAPELESS_KEY']}&sessionTTL=180&proxyCountry=ANY"
)


class ScrapelessLoader(ChromiumLoader):
    def __init__(self, urls, **kwargs):
        kwargs.pop("backend", None)
        super().__init__(urls, backend="playwright", **kwargs)
        self.backend = "scrapeless"

    async def ascrape_scrapeless(self, url: str, browser_name: str = "chromium") -> str:
        from playwright.async_api import async_playwright

        async with async_playwright() as p:
            browser = await p.chromium.connect_over_cdp(CDP)
            page = await browser.new_page()
            await page.goto(url, wait_until=self.load_state)
            html = await page.content()
            await browser.close()
            return html


fetch_node.ChromiumLoader = ScrapelessLoader

graph = SmartScraperGraph(
    prompt="List the quote authors on this page.",
    source="https://quotes.toscrape.com/",
    config={
        "llm": {
            "model": "ollama/qwen2.5:0.5b",
            "temperature": 0,
            "format": "json",
            "model_tokens": 4096,
        },
        "verbose": False,
        "headless": True,
    },
)
result = graph.run()
print("keys:", sorted(result))
print("authors:", [item["author"] for item in result["content"]][:4])
text Copy
keys: ['content']
authors: ['Albert Einstein', 'J.K. Rowling', 'Jane Austen', 'Marilyn Monroe']

著者は正確に戻り、構造は正しいです。このモデルからの引用テキストはあまり信頼性が高くなく — 0.5Bパラメータモデルは長いリスト上で文字列をクリップし、マージします — が、取得レイヤーは全ページを配信し、モデルが制限因子となります。model キーをより大きなローカルモデルまたはホスト型のものに移動すると、同じグラフが同じローダーを通じてクリーンなテキストを生成します。

構造化された出力が全てがここでのポイントです:グラフは パースされたHTMLドキュメント を読み取ります。これはリモートブラウザがレンダリングしたものであり、プレーンなHTTPクライアントが受け取った生のマークアップではありません。formatjson に設定すると、モデルに対して JSONインターチェンジフォーマット に準拠した出力を要求します。これにより、結果が直接サブスクリプト可能になり、パースする必要のある文字列にはなりません。

結論

ScrapeGraphAIの取得レイヤーは、チュートリアルが示唆するよりもはるかに構成可能であり、構成ポイントは loader_kwargs ではありません — それは backend 文字列で、メソッド名に解決します。ascrape_scrapeless メソッドを持つ一つのサブクラスは、取得をクラウドブラウザに移動させ、fetch_node.ChromiumLoader の再バインディングがグラフにそれを使用させます。

結果が変わっていないように見える場合は、最初に再バインディングを確認してください。決してバインドされないサブクラスは静かに失敗し、症状は以前と同じように正確に機能するグラフです。前述の中間ステップの独自のローダーを確認すると、取得問題とモデル問題を一回の実行で分離します。

ブラウザ制御が標準として向かう先については、 WebDriver BiDi仕様 を追跡する価値があります。PlaywrightおよびScraping Browserガイド では接続自体についてより深く説明しており、計画の詳細は Scrapeless料金ページ にあり、セッションパラメータは Scrapelessドキュメント にあります。

FAQ

Q: クラウドパスを使用するためにブラウザをインストールする必要がありますか?

いいえ。pip install scrapegraphai はPlaywrightクライアントを提供し、connect_over_cdp が必要とするのはそれだけです。なぜなら、ドライブされるブラウザはすでにリモートで実行中だからです。通常のローカルローダーを実行したい場合のみ playwright install chromium が必要です。

Q: なぜ私のカスタムローダーがグラフによって無視されるのですか?
ほとんど常に fetch_node.ChromiumLoader が再绑定されていなかったためです。 FetchNode は名前でクラスをインポートし、その名前を呼び出すため、サブクラス化だけでは何も変わりません — ノードは元のクラスを構築し続けます。グラフを構築する前に、モジュール上の属性を再绑定してください。

Q: サブクラスの代わりに loader_kwargs を使用できますか?

プロキシやブラウザ起動オプションの場合、はい — loader_kwargsChromiumLoader に直接流れます。ただし、fetch をリモートブラウザにリダイレクトすることはできません。なぜなら、スタックメソッドが chromium.launch() を呼び出し、常にローカルプロセスを起動するからです。宛先を変更するとメソッドも変更され、つまりサブクラスが必要になります。

Q: SmartScraperGraph 以外のグラフでも機能しますか?

はい。再绑定はノードレベルで行われ、FetchNode は他のグラフタイプのエントリノードでもあるため、URL を取得するすべてのグラフは属性がバインドされると同じローダーを通過します。

Q: sessionTTL は何を制御しますか?

リモートブラウザのセッションがオープンのままでいる時間(秒)。単一の fetch にかかる時間よりも快適な範囲で設定してください。セッションは接続が終了するかウィンドウが期限切れになると閉じられます。どちらが先でも構いません。

Q: Fetch の間にクッキーやログインセッションを保持できますか?

storage_stateFetchNode によってすでに渡され、サブクラスコンストラクターに変更なしで到達するため、標準の Playwright ストレージステートファイルは機能します。リモートブラウザの起動時ではなく、リモートブラウザのコンテキストを作成する際にそれを適用してください。なぜなら、リモートブラウザはあなたのコードによって起動されていないからです。

Q: 0.5B のローカルモデルは、本物の抽出に十分ですか?

シンプルな形状の短いページの場合、上記のように使用可能な構造を生成します。長いページやネストされたスキーマでは劣化し、テキストがクリップされ、フィールドがマージされます。小さなローカルモデルは、fetch レイヤーを安価に反復するための方法と見なし、その後本番実行用に model キーを切り替えてください。

Scrapelessでは、適用される法律、規制、およびWebサイトのプライバシーポリシーを厳密に遵守しながら、公開されているデータのみにアクセスします。 このブログのコンテンツは、デモンストレーションのみを目的としており、違法または侵害の活動は含まれません。 このブログまたはサードパーティのリンクからの情報の使用に対するすべての責任を保証せず、放棄します。 スクレイピング活動に従事する前に、法律顧問に相談し、ターゲットウェブサイトの利用規約を確認するか、必要な許可を取得してください。

最も人気のある記事

カタログ