Playwrightレビュー:ChromiumでJavaScriptレンダリングはできるが、クロール処理は自前で用意する必要がある

最終更新日 August 18, 2026
Playwrightレビュー:ChromiumでJavaScriptレンダリングはできるが、クロール処理は自前で用意する必要がある
AI要約
PlaywrightはMicrosoftのブラウザー自動化フレームワークです。Apache 2.0ライセンスのTypeScriptファーストなライブラリで、実ブラウザーを起動し、ひとつのAPIで操作し、JavaScriptの実行後のページを返してくれます。エンドツーエンドテスト用のフレームワークとして紹介されていますが、HTTPリクエストでは本来データがあるはずの場所が空のまま返ってくるような場面で、裏側のエンジンとして密かに頼られることが多いツールでもあります。形としてはPuppeteerやSeleniumと競合する存在で、HTTPクライアントを解析するのではなく、実ブラウザーをスクリプトで操作するタイプです。私は microsoft/playwright 1.56.0 を、固定された一連のスクレイピングテストにかけました。対象は、ページネーション付きの静的カタログ、記事、JavaScriptで描画されるカタログ、JSON API、500エラーの壊れたページ、小さなクロールグラフ、そして公開練習サイト2件です。実行環境は Node v22.22.3、macOS arm64、Chromiumのみでした。

PlaywrightはMicrosoftのブラウザー自動化フレームワークです。Apache 2.0ライセンスのTypeScriptファーストなライブラリで、実ブラウザーを起動し、ひとつのAPIで操作し、JavaScriptの実行後のページを返してくれます。エンドツーエンドテスト用のフレームワークとして紹介されていますが、HTTPリクエストでは本来データがあるはずの場所が空のまま返ってくるような場面で、裏側のエンジンとして密かに頼られることが多いツールでもあります。形としてはPuppeteerやSeleniumと競合する存在で、HTTPクライアントを解析するのではなく、実ブラウザーをスクリプトで操作するタイプです。

私はmicrosoft/playwright 1.56.0を、固定された一連のスクレイピングテストにかけました。対象は、ページネーション付きの静的カタログ、記事、JavaScriptで描画されるカタログ、JSON API、500エラーの壊れたページ、小さなクロールグラフ、そして公開練習サイト2件です。実行環境は Node v22.22.3、macOS arm64、Chromiumのみでした。レンダリング面は問題なく通過しましたが、クロール面はそもそも備わっていません。このギャップこそが、このツールを使う前に理解しておくべき最も重要な点です。

目立ったポイント

結果を見て特に印象的だったのは2つで、方向性は少しずつ異なります。

1つ目は、想定どおりのブラウザー結果です。ここでは、私が設定した待機条件の範囲内で評価しました。page.goto(..., { waitUntil: 'domcontentloaded' }) の後、動的フィクスチャのテストでは #dynamic-products article.product-card を待機し、公開サイトの Quotes to Scrape では .quote を待ちました。アプリ固有のセレクターが出現した後に、テストはフィクスチャ8件中8件、公開サイトの引用文10件を取得しました。フィクスチャの結果は、8件の正解データに対して recall 1.0 でした。専用のポーリングループは不要でしたが、Playwrightが「準備完了」を自動判定してくれるわけではなく、完了条件自体はテスト側が与えていました。なお、フルページのスクリーンショットも1回目の呼び出しで保存できました。

2つ目は browserContext.request を使った結果です。具体的には、Chromiumを起動してブラウザーコンテキストが存在する状態で ctx.request.get(...) を実行しました。これはフィクスチャのJSONエンドポイントに直接アクセスし、ページを生成したり描画したりせずに8件中8件の商品を返しました。この方法はDOM処理を省けますが、このハーネスではブラウザープロセス自体のコストまでは省いていません。コンテキストに紐づくリクエストクライアントは、ブラウザーページとCookie状態を共有できます。一方、単独の playwright.request.newContext() はブラウザーコンテキストを不要にしますが、セッションを自動共有するわけではありません。今回のテストは前者のみを扱いました。

また、Playwrightにはクロールキュー、データセット書き出し、自動スロットリングの仕組みはありません。私のクロールグラフのテストでは、内部リンクを辿り、深さを記録し、再訪を避けて12ページに到達しましたが、幅優先探索の実装は私が書いたテストコードです。Playwrightはページを開いて中身を確認する役割までで、フロンティアの永続化、URLポリシー、リトライ、スケジューリングは別レイヤーの仕事です。

Playwrightの実体

このツールはGitHub上の microsoft/playwright で、TypeScriptで書かれ、Apache 2.0ライセンスのもとでMicrosoftがメンテナンスしています。今回検証したビルドは 1.56.0 で、日付は 2026年7月9日です。以下の結果は、このビルドに対するものとして報告しており、後続バージョンとの互換性を保証するものではありません。

公式の位置づけは明快です。Playwrightは、Chromium、Firefox、WebKitをひとつのAPIで操作できる、Webテストおよび自動化のためのフレームワークです。主な使い方は、fixture、assertion、trace viewer を備えたテストランナーです。スクレイピング用の基盤として使う場合は、ドキュメントにある Library mode に従い、テストハーネスの外で chromium.launch()contextpage の順に扱います。このレビューでは公開APIのみを使いました。バージョンをまたいだ互換性テストは行っていないため、ここで触れた挙動がすべてのリリースで安定しているとまでは言いません。

他の比較記事ではマルチエンジン対応が大きな売りになりますので、そこは正確に言っておきます。PlaywrightはひとつのAPIから3つのブラウザーエンジン、Chromium、Firefox、WebKitを操作でき、JavaScriptに加えてPython、Java、.NET向けのファーストクラスなクライアントも提供しています。これは公式に示されている内容であり、構成としての大きな差別化要素です。今回の検証で実際に触れた範囲は、次のように限定されます。

機能このレビューでの扱い
Chromium エンジン検証済み — すべてのテストをChromiumで実行
Firefox エンジンドキュメント上は対応、ここでは未検証
WebKit エンジンドキュメント上は対応、ここでは未検証
3エンジン共通の単一APIドキュメント上は対応、ここでは未検証
Python、Java、.NET クライアントドキュメント上は対応、ここでは未検証
プロキシ未テスト
複数コンテキストの並列スケール未テスト
API中心スクレイピング向けのネットワークインターセプト未テスト

ターゲットがSafariのWebKitで異なる挙動を示す場合や、チームがPythonを使っている場合、その広さはPlaywrightの強みになります。ただし、今回の結果をFirefoxやWebKitの互換性証明と受け取らないでください。そこは未検証です。

内部ではどう動くのか

考え方としては、スクリプトで操作するブラウザーエンジンです。chromium.launch() がブラウザープロセスを起動します。context はCookie、ストレージ、キャッシュを持つ独立したセッションで、page はその中のタブです。page.goto(url) を呼び、アプリが使える状態になったことを示す条件を待ち、page.$$eval などのヘルパーでDOMを読み取ります。これはHTTPレスポンスを解析するよりも実ブラウザーに近い動作ですが、環境を完全再現するものではありません。ヘッドレスの有無、ビューポート、ロケール、フォント、プロファイル状態、TLS/ネットワーク経路、サイト側の防御などで、返される内容はまだ変わりえます。このレビューでは、アンチボット挙動や本番ブラウザーとの同等性は検証していません。

page.screenshot() は、レンダリング済みページを全体または一部だけ保存できます。私の実行では最初の呼び出しで正常に動きました。先ほど触れた context.request.get は、同じコンテキストのCookieを使いつつレンダリングをスキップするため、「ページを読み込んでDOMを取る」処理と「JSONエンドポイントを直接叩く」処理を、ツールを切り替えず1本のスクリプトにまとめられます。

一方で、内蔵されていないのがクロール機構です。リクエストスケジューラ、訪問済みURLの永続管理、丁寧なアクセス制御、書き出しパイプラインはありません。範囲を絞った巡回は簡単に書けますが、実運用向けのフロンティア処理には、URL正規化、リダイレクト処理、リトライ、スコープルール、スロットリング、復旧処理も必要です。そのレイヤーは自分で作るか、ブラウザーエンジンを包む別のフレームワークを使う必要があります。

セットアップと導入の現実

インストールは2段階で、負担の大半は2つ目にあります。npm install playwright でライブラリを入れ、別途 npx playwright install でブラウザービルドをダウンロードします(私の環境ではChromium)。npmパッケージだけを「実行可能なシステム全部」と考えず、ディスク容量、ダウンロード時間、CIでのブラウザキャッシュ、プロセス終了処理まで見積もるべきです。

Playwrightをスクレイパーとして入れたつもりで、最初にチュートリアルを追うと、テストファイルと expect() のアサーションから始めることになります。一方、スクレイピング用のコードはライブラリAPIを直接使います。どちらも公式ドキュメントにありますが、例を探すときやデプロイ手順を選ぶときに、この違いはとても重要です。

今回の実行で実感として良かったのは、ブラウザーコンテキストでセッションが分離されること、async呼び出しがきれいにつながること、スクリーンショットが1回で取れること、そしてHTTP 500でもレスポンスオブジェクトから確認できることでした。逆に運用面の弱点は、構文ではなく導入手順にありました。ブラウザービルドを別途入れ、そのライフサイクルをライブラリとは独立して管理する必要があります。

実地での結果

計測結果のチャート: 3つのデータ経路を検証

ローカルの数値はすべて 127.0.0.1 上のフィクスチャサーバーに対して実行され、クロール前に正解データが記録されていました。実験用ハーネスの詳細は run_playwright_material_tests.mjs にあり、コミット済みの raw artifacts には正解データと各テストの出力が含まれています。これらはあくまで1台のマシンで1回実行した、著者による観測です。リンクは再現手段を公開するもので、広範なベンチマークとして一般化するものではありません。

テスト対象結果
静的カタログ + ページネーションローカルフィクスチャ商品12/12件、recall 1.0
記事抽出ローカルフィクスチャタイトル + 3/3段落、不要要素は別扱い
動的JSページ(ネイティブレンダリング)ローカルフィクスチャ8/8件、recall 1.0、フルページスクリーンショット保存
動的JSON API(page.requestローカルフィクスチャ8/8件、recall 1.0、DOMは描画せず
HTTP 500の処理ローカルフィクスチャステータス500を確認可能、ナビゲーションは例外にならず
クロールグラフ(手書きBFS)ローカルフィクスチャ12ページ、深さ {0:1, 1:4, 2:7}
Books to Scrape公開デモ20件の商品
Quotes JS(JSレンダリング)公開デモ10件の引用、ネイティブ描画

ページネーションのループは次のリンクを明示的に辿っており、Playwrightが自動でページを見つけたわけではありません。記事のセレクターは、ナビゲーション要素やフッターの文言を本文結果から分離してくれました。失敗ルートでは、ナビゲーションは例外を投げずにステータス500のレスポンスオブジェクトを返したため、ログに残すか、再試行するか、そのまま続けるかは呼び出し側が判断できます。2つの公開練習サイトは、表に示した件数を返しました。

はっきりさせておきたい境界があります。ここでのすべては、1台のマシン上でChromiumのみを使い、1回だけ実行しました。機能表では、ドキュメント上の広さと実際に触れた挙動を分けて記載しています。別のPlaywrightビルドで再実行していないため、バージョン差の結論は導けません。また、各テストの所要時間もベンチマークとしては載せていません。1台のノートPCで1回計っただけでは、速度比較の根拠にはならないからです。

準備完了は抽出条件の一部

動的な結果は、単にブラウザー遷移が終わったというだけではなく、欲しいデータの準備が整ったことを示す待機条件に依存していました。ローカルカタログでは、ハーネスが waitUntil: 'domcontentloaded' で遷移したあと、15秒タイムアウト付きで waitForSelector('#dynamic-products article.product-card') を呼び出しています。公開版のQuotes JSも同じナビゲーション状態を使い、20秒タイムアウトで .quote を待ちました。抽出は、そのセレクターが現れてから行っています。

この違いは、スクリプトを実運用へ適用するときにとても重要です。domcontentloaded は初期HTMLの解析完了を意味するだけで、遅延APIレスポンスが届いたこと、hydrationが完了したこと、無限スクロールが止まったこと、仮想化された行が表示領域に入ったことまでは示しません。1つの要素が見つかれば十分なら、セレクター待機は便利です。しかし、完全性が既知のレスポンス、件数、アプリ状態、あるいは通信の静穏期間に依存するなら、その条件を待つべきです。条件は出力の契約に結びつける必要があります。「少なくとも1件カードがある」と「期待する全ページが読み込まれた」は別の主張です。

システム図: 準備完了は抽出契約の一部

タイムアウト処理も呼び出し側の責任です。今回のテストでは有限のセレクタータイムアウトを使いましたが、リトライポリシーまでは調べていませんし、遅いページと永続的に変わったセレクターも区別していません。本番向けのラッパーであれば、どの準備条件が失敗したのかを記録し、原因特定に必要なページ状態を保存し、再遷移が安全かどうかを判断すべきです。Playwrightが提供するのはイベントとDOMであって、「この仕事での完全なデータ」が何を意味するかまでは判断できません。

この境界は、各抽出処理の横に明記しておくべきで、タイムアウト任せの暗黙仕様にしてはいけません。

API経路にも、対応する契約があります。ctx.request.get が適切だったのは、ブラウザーコンテキストがすでに存在し、セッション共有が有用だったからです。もし、ブラウザーのセッションがなくてもデータエンドポイントが動くと分かったなら、単独のリクエストコンテキストは別の設計であり、ライフサイクルやCookieの扱いも異なります。今回その2つを比較はしていません。「DOMを描画していない」という事実をまず受け止め、そのうえで、より広いワークフロー全体にブラウザープロセスが必要かを別途判断してください。

クロールという問題

クロールグラフの結果は、Playwrightをどう捉えるべきかを決める材料です。12ページ、3段階の深さ、結果は正しい。そして、ページを辿るロジックはすべて私が書きました。Playwrightが担ったのは「このURLを開いて読む」部分だけで、キュー、訪問済みセット、深さ管理は私の実装です。

小規模で範囲が限定された仕事なら、それで問題ありません。しかし、クロール規模になると、ブラウザーライブラリの上にクローラーを自作するか、すでにクロール機能を持つものとPlaywrightを組み合わせることになります。公式に近い定番の構成は Crawlee で、Playwright(およびPuppeteer)を、実際のリクエストキュー、データセット保存、自動スロットリングと一緒に包みます。レンダリングはPlaywrightに任せ、オーケストレーションは借りる形です。もし、キューを後付けではなくフレームワーク本体に組み込みたいなら、それは Scrapy の設計思想そのものです。ただしScrapyはHTTPファーストで、JavaScriptを自力では描画しません。ここで言いたいのはPlaywrightが不足しているというより、「ブラウザー自動化」と「クロール」は別の仕事であり、Playwrightが名乗っているのはそのうち1つだけだということです。

システム図: クロール層はあなたの担当

12ページのBFSは、その責任範囲を具体的に示しています。制御されたグラフに対して、キュー、訪問済みセット、深さ管理を自前で用意しました。本番のフロンティアでは、URLの正規化、リダイレクト処理、許可ホスト、重複キー、リトライ、並行実行、ホスト単位の遅延、永続化、再開時の挙動まで定義しなければなりません。出力の選択も別問題です。フィクスチャがJSONとCSVを書き出したのはハーネスがそうしたからであって、Playwrightにデータセット抽象化があるからではありません。

セッション設計もラッパーの挙動に影響します。1つのブラウザーに複数のコンテキストを持たせれば、Cookieやストレージは分離されますが、このレビューでは並列コンテキストのスケールや障害分離は測っていません。コンテキストを再利用すればログイン状態を保ってセットアップを減らせる一方、別コンテキストにすればジョブ間の状態漏れを防げます。これらはPlaywrightがコンテキストという基盤を提供していても、クロール側のポリシーです。実際に動かすブラウザービルドとデプロイ環境で、そのライフサイクルを測るべきです。

長所と短所

長所:

  • 実際のChromiumエンジンでJavaScriptを実行できる。動的ターゲットは、準備条件として使ったセレクターに到達した。
  • 最初の呼び出しでフルページスクリーンショットを取得できた。
  • セレクターで、制御されたフィクスチャから静的カタログと記事の必要項目を期待どおり抽出できた。
  • browserContext.request でページを描画せずにJSONエンドポイントへ到達でき、しかも起動済みブラウザープロセスはハーネス内に維持できた。
  • 失敗レスポンスに強い。HTTP 500を確認でき、ナビゲーションは例外にならなかった。
  • 3エンジン対応(Chromium、Firefox、WebKit)をひとつのAPIで提供し、Python、Java、.NETクライアントもある(いずれも公式には対応、ただし今回使ったのはChromiumのみ)。
  • Apache 2.0で、Microsoftがメンテナンスしている。
  • library modeに入れば開発体験は素直。エンジン間でAPIが共通で、asyncも扱いやすく、スクリーンショットも簡単。

短所:

  • クロール用のキュー、データセット、自動スロットリングが標準ではない。クロール規模の仕事は自作かCrawleeのようなラッパーが必要。
  • ブラウザー自体が重い。バイナリのダウンロードとページごとのコストが、HTTPのみのツールに対する実質的な負担。
  • 既定の文脈はテストランナーであり、スクレイピングでは library mode の存在を知って自分で外に出る必要がある。
  • ここで検証したのは Playwright 1.56.0 と Chromium のみ。バージョン違い・エンジン違いの同等性は未検証。
  • スキーマに沿った構造化JSON出力は自前では持たない。セレクターを作り、データ形状を整えるのは利用者側。

どんな人向けか、どんな人は避けるべきか

JavaScript実行後にデータが現れるページを描画したい、あるいはDOMデータに加えてスクリーンショットも取りたいなら、Playwrightは十分に有力な候補です。すでにPlaywrightのテストを使っているチームなら、同じ概念やセレクターの扱いを library mode でも再利用できます。Python、Java、.NETクライアントも公式オプションですが、このレビューで実際に使ったのはNodeとChromiumだけです。

ただし、次の3つのケースでは別レイヤーを検討してください。必要なデータがすでにHTTPレスポンスに含まれているなら、HTTPファーストのツールを使えばブラウザー起動やレンダリングのオーバーヘッドを避けられます。そのカテゴリのクローラーライブラリとしては Colly があり、記事抽出なら Trafilatura が向いています。キューイング、永続化、スロットリングが必要なら、クローラーフレームワークかPlaywrightラッパーを使うべきです。セレクターを保守せずにスキーマ形式の出力がほしいなら、マネージド抽出サービスを比較してください。これらの代替案は、このレビューではベンチマークしていません。

PlaywrightとPuppeteerのどちらにするかを迷っているなら、それはそれで別の比較です。私たちの side-by-side comparison では、同じフィクスチャで両者を走らせ、最終的にどこで差が出るのかまで確認しています。

代替案と、マネージド抽出の位置づけ

Playwrightは無料で、Apache 2.0ライセンス、セルフホスト型です。ブラウザーデプロイ、セレクター、準備条件、クロールコード、更新対応、障害処理は自分で持つことになります。このレビューでは、アンチボット性能や、マネージドサービスとの総運用コスト比較は行っていません。

オープンソースの中では、用途ごとの比較が有効です。ブラウザーを使ったクロール規模の仕事なら、CrawleeはPlaywrightに足りないキューとデータセットを補います。LLM向けMarkdownをブラウザーから直接作りたいなら、Crawl4AI はブラウザーを動かして、そのためのMarkdownを出力します。複数の候補をまとめて比較したいなら、open-source scraper roundup がカテゴリ別に整理しています。

開示事項として、Thunderbit はこのレビューの発行元の製品ですが、このPlaywrightフィクスチャでは実行していません。Thunderbitはマネージド抽出のカテゴリに属し、サービス側がレンダリングを担ってページ本文やスキーマ化されたレコードを返します。一方でPlaywrightは、ブラウザー操作とセレクター設計を開発者側に残します。したがって比較対象は、ホスティング形態、出力の形、コストモデルであり、このレビューから導かれる性能結果ではありません。

Webデータ抽出にThunderbitを試す

結論

ターゲットにブラウザーエンジンが必要で、準備条件、セレクター、クロールのオーケストレーションを自分で管理できるなら、Playwrightを使うべきです。結果表が示すとおり、この著者実行の検証では、Chromiumのlibrary modeが、静的、動的、API、スクリーンショット、失敗系の制御されたフィクスチャを期待どおりに処理しました。

ただし、証拠の範囲は明確に保つ必要があります。実行したのはChromiumとNodeのみ、12ページの巡回は手書きBFSに依存し、browserContext.request はページ描画を飛ばしたものの、起動済みブラウザープロセスはそのまま使っていました。そして、動的抽出はすべて明示した準備条件セレクターに依存しています。これらの制約のもとでは、Playwrightはこのレビューで扱った「ブラウザーの基本部品」であり、測定済みのエンドツーエンドクロールシステムではありません。

Webデータ抽出にThunderbitを試す Get Started Free

FAQ

Playwrightでスクレイピングする場合でも待機は必要ですか? はい。ブラウザーがページを開いただけでは、アプリのデータ準備完了までは分かりません。今回のテストでは domcontentloaded まで遷移し、そのあと抽出前に対象固有のセレクターを待ちました。本番ページでは、レスポンス、ロケーターの状態、アプリイベントなど、別のシグナルが必要になることがあります。

Playwrightだけでサイト全体をクロールできますか? 標準機能だけではできません。組み込みのリクエストキュー、データセット書き出し、自動スロットリングはありません。私のクロールグラフのテストが12ページ、深さ {0:1, 1:4, 2:7} まで進めたのは、幅優先探索を手書きしたからです。クロール規模の仕事では、実際のクロール層を持つ Crawlee と組み合わせるか、別のクローラーフレームワークを使ってください。

browserContext.request と単独の request context はどう使い分けますか? 既存のブラウザーコンテキスト内のページとCookieを共有したいHTTP呼び出しには browserContext.request を使います。ブラウザーを起動せず、ブラウザーページとのCookie自動共有も不要なら、playwright.request.newContext() を使ってください。今回テストしたのは前者のみです。

FirefoxとWebKitは今回テストしましたか? いいえ。すべてのテストは1台のマシンでChromiumのみ、1回実行でした。Playwrightの3エンジン対応(Chromium、Firefox、WebKit)とPython、Java、.NETクライアントは公式にある機能として記載していますが、FirefoxとWebKitの同等性、プロキシ、並列スケール、ネットワークインターセプトは今回の数値では検証していません。

このレビューで対象にした環境は何ですか? Playwright 1.56.0、Node v22.22.3、macOS arm64、そしてChromiumのみです。Firefox、WebKit、プロキシ、並列スケール、アンチボット挙動、さらに新しいPlaywrightバージョンは対象外でした。インストールにはライブラリ本体に加えて、ブラウザービルドの別途ダウンロードが必要でした。

Ke
Ke
Thunderbit の CTO | シニアデータサイエンティスト & ML エキスパート 機械学習とデータサイエンスで約10年の経験を持つ Ke Shen は、コロンビア大学の卒業生であり、Walmart Labs の元シニアデータサイエンティストです。Python、R、Java、統計学における深い専門性は同業者からも高く評価されており、理論段階の複雑な AI アルゴリズムを本番運用レベルのアーキテクチャへと落とし込むための、実践に裏打ちされた知見を共有しています。
目次
Thunderbit · AIウェブデータエージェント

1クリックで、どのページからもデータを抽出

25万人以上のユーザーに支持されています
無料プランあり
Webページからスプレッドシートへ
必要な内容を伝えるだけ。ThunderbitのAIエージェントが抽出し、Excel、Google Sheets、Airtable、Notionへ書き出します。すぐに無料で始められます。
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week