DOMからのデータ抽出

以下では、Playwright を用いて DOM からデータを抽出するための実践的な手法を、概念から具体例・ベストプラクティスまで体系的に解説します。


1. 基本概念:Playwright における「ブラウザ側」と「Node.js 側」

Playwright では テスト/スクレイピングスクリプト(Node.js 側)ブラウザページ(DOM 側) が別プロセスで動きます。page.evaluate() を使用すると、ブラウザ側で JavaScript を実行し、その戻り値を Node.js 側にシリアライズして受け取れます playwright.dev


2. 要素の特定(ロケーター)

  • 推奨ロケーター API

    • page.getByRole(), page.getByText(), page.getByLabel() などアクセシビリティやテキストに基づく高レベル API playwright.dev

  • CSS/XPath セレクター
    必要に応じて page.locator('css=div.item')page.locator('xpath=//li') も利用できます。

  • 自動待機
    Locator は参照時に常に最新 DOM を取得し、内部で「表示・安定・イベント受信可能」などの条件が満たされるまで自動的に待機します playwright.dev


3. 単一要素からのデータ抽出

ts
// 見出しテキストを取得 const title = await page.getByRole('heading', { level: 1 }).textContent(); // 属性値を取得 const href = await page.locator('a.download').getAttribute('href');
  • locator.textContent():改行や隠し要素を含む raw テキストを取得。

  • locator.innerText():CSS の display:none などで非表示の要素を除外した整形済みテキストを取得。

  • locator.getAttribute(name):属性値を取得(例:画像の src, リンクの href など)。


4. evaluate()$eval() 系による柔軟な抽出

ts
// table 行ごとにセル値を配列で取得 const rows = await page.$$eval('table#orders tbody tr', trs => trs.map(tr => Array.from(tr.cells, td => td.textContent?.trim() ?? '')) );
  • page.evaluate(fn, …args):ブラウザ環境で任意の JS 関数を実行し結果を返却 playwright.dev

  • page.$eval / page.$$eval:セレクターで要素(複数要素)を特定してから関数を適用。

  • 引数の受け渡し:シリアライズ可能な値や JSHandle を渡して複雑なロジックを実装可能です。


5. 複数要素のバルク取得

  • locator.allTextContents()locator.allInnerTexts() を使うと、指定 Locator に一致するすべての要素から文字列をまとめて取得できます(大量 DOM でも高速)。

  • page.$$eval と同様、戻り値はブラウザ側でオブジェクト → JSON へ変換されて返ります。


6. 動的サイトへの対応

  1. レンダリング完了まで待機

    • 自動待機が基本ですが、SPA でリストが非同期ロードされる場合は page.waitForSelector('.list-loaded') などの明示的待機を併用します。

  2. ポーリング間隔とタイムアウト

    • デフォルトタイムアウト(30 s)を超える場合は locator.waitFor({ timeout: 60_000 }) などで延長。


7. フレーム・Shadow DOM の取り扱い

  • iframe 内const frame = page.frameLocator('#ad-frame'); … として内部 DOM を扱います playwright.dev

  • Shadow DOMlocator('css=book-app >> shadow=book-list').locator('li') のように >> shadow= で階層を横断可能。


8. 大規模スクレイピング時の実践テクニック

テーマ 推奨アプローチ
アンチボット対策 ʻstealthʼ プラグイン、ユーザーエージェントの分散、遅延クリックなど browserless.io
ページネーション 再帰/ループで「次へ」リンクをクリックし、都度抽出・保存
並列実行 Promise.all() で複数 URL を同時に処理しつつ、同時接続数を制御
リソース節約 page.route('**/*.{png,jpg,css}', route => route.abort()) で不要リソースをブロック

9. メモリ管理とハンドル

  • evaluateHandle()JSHandle を取得した場合は、不要になったら handle.dispose() で破棄してリークを防止 playwright.dev

  • ElementHandle vs Locator:前者は「静的参照」、後者は「都度検索+自動待機」。スナップショットが欲しい場合のみ ElementHandle を使用すると良い playwright.dev


10. 法的・倫理的注意

  • robots.txt / 利用規約 を必ず確認し、禁止されているページのクロールや高頻度アクセスを避ける。

  • 個人情報・クッキー・ログイン済みセッションの取り扱いには十分配慮し、社内ポリシーを遵守する。


まとめ

Playwright では Locator ベースの API と evaluate() 系 API を組み合わせることで、静的/動的どちらのサイトからも効率よく DOM データを抽出できます。まずは Locator で正確に要素を絞り込み、必要に応じて evaluate() で複雑なロジックをブラウザ側にオフロードすると、可読性とパフォーマンスを両立できます。

ChatGPT4o 生成日:2025/06/22