AI

Puppeteerの使い方完全ガイド【インストールから応用まで】

Puppeteerの使い方完全ガイド【インストールから応用まで】

もしWebサイトの自動操作が必要なとき、手作業で何時間もかかる作業を想像してみてください。例えば、毎日数十件のWebサイトから特定データを取得する。あるいは、新しい機能がリリースされるたびに、手動でWebアプリケーションの全機能をテストする。これらの作業は時間と労力を大きく消費します。

しかし、Puppeteerがあれば、これらの反復的な作業を数行のコードで自動化できます。Webブラウザをプログラムから直接操作し、人間が行うクリック、入力、スクロールといった動作を正確に再現するのです。これにより、開発者はより創造的で価値の高いタスクに集中できるようになります。

Puppeteerとは

Puppeteerは、Google ChromeやMozilla FirefoxをJavaScriptで制御するためのライブラリです。ヘッドレスブラウザ、つまりGUI(グラフィカルユーザーインターフェース)なしのブラウザをデフォルトで操作します。これにより、バックグラウンドでWebページを開き、様々な操作を実行できます。

具体的には、ChromeのDevTools ProtocolやWebDriver BiDiというプロトコルを通じてブラウザと通信します。これにより、Webページのスクリーンショット撮影、PDF生成、フォームの自動入力、Webスクレイピング、UIテストといった幅広い用途で利用可能です。PuppeteerはNode.js環境で動作し、JavaScriptを使って直感的にブラウザを制御できます。

このライブラリは、もともとChrome開発チームによって開発されました。Webブラウザの自動化というニーズが高まる中で、よりシンプルで強力なAPIを提供するために誕生したのです。

インストール方法

Puppeteerのインストールは非常に簡単です。Node.jsとnpm(またはYarn、pnpmなどのパッケージマネージャ)がインストールされている環境であれば、以下のコマンドを実行するだけで準備が整います。

npm i puppeteer

このコマンドを実行すると、Puppeteer本体とともに、互換性のあるChromium(Google Chromeのオープンソース版)が自動的にダウンロードされます。これにより、別途ブラウザをインストールする手間なく、すぐにPuppeteerを使い始められます。

もし、すでにシステムにインストールされているChrome/Firefoxを利用したい場合や、ブラウザのダウンロードをスキップしたい場合は、puppeteer-coreを使用します。

npm i puppeteer-core

puppeteer-coreをインストールした場合、ブラウザは自動でダウンロードされません。そのため、Puppeteerを起動する際に、使用するブラウザの実行パスを明示的に指定する必要があります。

パッケージマネージャによっては、インストールスクリプトの実行がデフォルトでブロックされることがあります。この場合、ブラウザが自動的にダウンロードされない可能性があります。その際は、以下のコマンドを手動で実行してブラウザをインストールしてください。

npx puppeteer browsers install

または、package.json"allowScripts""puppeteer"を追加して、インストールスクリプトの実行を許可する方法もあります。

基本的な使い方

Puppeteerの基本的な操作は、ブラウザの起動、新しいページの作成、URLへの移動、そしてブラウザの終了という流れです。ここでは、最低限知っておくべき主要なコマンドをいくつか紹介します。

1. ブラウザを起動し、ページを開く

まず、Puppeteerをインポートし、ブラウザを起動します。puppeteer.launch()は新しいブラウザインスタンスを起動し、そのインスタンスを操作するためのオブジェクトを返します。browser.newPage()は新しいタブ(ページ)を開きます。

import puppeteer from 'puppeteer';

async function runBasicScript() {
  // ブラウザを起動します。headless: true はGUIなしで実行する設定です。
  const browser = await puppeteer.launch({ headless: true });
  // 新しいページ(タブ)を開きます。
  const page = await browser.newPage();

  console.log('ブラウザを起動し、新しいページを開きました。');

  // ここに他の操作を追加します...

  // ブラウザを閉じます。
  await browser.close();
  console.log('ブラウザを閉じました。');
}

runBasicScript();

2. 特定のURLに移動する

page.goto()メソッドを使って、指定したURLにページを移動させます。

import puppeteer from 'puppeteer';

async function navigateToUrl() {
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();

  // ページをGoogleのトップページに移動させます。
  await page.goto('https://www.google.com/', { waitUntil: 'domcontentloaded' });
  console.log('Googleのトップページに移動しました。');

  await browser.close();
}

navigateToUrl();

waitUntil: 'domcontentloaded'は、ページのDOMが完全に読み込まれた時点で待機を終了するオプションです。これにより、ページのレンダリング完了を待つことができます。

3. スクリーンショットを撮る

page.screenshot()メソッドで、表示されているWebページのスクリーンショットを画像ファイルとして保存できます。

import puppeteer from 'puppeteer';

async function takeScreenshot() {
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();

  await page.goto('https://example.com/', { waitUntil: 'domcontentloaded' });

  // ページのスクリーンショットを'example.png'という名前で保存します。
  await page.screenshot({ path: 'example.png', fullPage: true });
  console.log('スクリーンショットを保存しました: example.png');

  await browser.close();
}

takeScreenshot();

fullPage: trueを設定すると、Webページ全体のスクリーンショットを撮ることができます。

4. ページ内の要素を操作する

Webページ内の要素を選択し、クリックしたり、テキストを入力したりできます。page.locator()を使って要素を特定し、click()fill()などのメソッドで操作します。

import puppeteer from 'puppeteer';

async function operatePageElements() {
  const browser = await puppeteer.launch({ headless: false }); // デバッグのためGUIを表示
  const page = await browser.newPage();

  await page.goto('https://www.google.com/', { waitUntil: 'domcontentloaded' });

  // 検索ボックスの要素を見つけ、テキストを入力します。
  // '::-p-aria(検索)' はアクセシブルな名前で要素を特定するセレクタです。
  await page.locator('::-p-aria(検索)').fill('Puppeteer'); 
  console.log('検索ボックスに「Puppeteer」と入力しました。');

  // 検索ボタン(またはEnterキー)をシミュレートします。
  await page.keyboard.press('Enter');
  // または、検索ボタンのセレクタを見つけてクリックすることもできます。
  // await page.locator('::-p-aria(Google 検索)').click();

  // 検索結果が表示されるまで待ちます。
  await page.waitForNavigation({ waitUntil: 'domcontentloaded' });
  console.log('検索結果ページに移動しました。');

  // 検索結果のタイトルを取得します。
  const firstResultTitle = await page.evaluate(() => {
    const titleElement = document.querySelector('h3'); // 最初のh3タグのテキストを取得
    return titleElement ? titleElement.textContent : 'タイトルが見つかりません';
  });
  console.log('最初の検索結果タイトル:', firstResultTitle);

  await browser.close();
}

operatePageElements();

page.evaluate()は、ブラウザのコンテキスト内でJavaScriptコードを実行するための強力なメソッドです。これにより、DOM要素から直接データを取得できます。headless: falseに設定すると、ブラウザが実際に開いて操作される様子を確認できます。

便利な使い方・応用例 3選

Puppeteerは、単なるWebページの自動化にとどまらず、様々な高度なタスクに応用できます。ここでは、実際の開発シーンで役立つ3つの応用例を紹介します。

1. 動的コンテンツのスクレイピングとアンチボット対策

多くのWebサイトはJavaScriptを使用してコンテンツを動的に生成します。Puppeteerはブラウザを完全にレンダリングするため、このような動的コンテンツも正確にスクレイピングできます。また、Webスクレイピングではアンチボットシステムに検出されないための対策も重要です。

import puppeteer from 'puppeteer';
// puppeteer-extraとpuppeteer-extra-plugin-stealthをインストールしてください
// npm i puppeteer-extra puppeteer-extra-plugin-stealth
import puppeteerExtra from 'puppeteer-extra';
import StealthPlugin from 'puppeteer-extra-plugin-stealth';

puppeteerExtra.use(StealthPlugin()); // ステルスプラグインを使用

async function scrapeDynamicContent() {
  const browser = await puppeteerExtra.launch({ headless: true });
  const page = await browser.newPage();

  // ユーザーエージェントを設定し、一般的なブラウザとして振る舞う
  await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36');
  await page.setViewport({ width: 1280, height: 800 }); // ビューポートサイズを設定

  // 例えば、JavaScriptでコンテンツが読み込まれるサイトにアクセスします
  await page.goto('https://example.com/dynamic-data', { waitUntil: 'networkidle2' });
  // 'networkidle2'は、2つのネットワーク接続が0.5秒以上アクティブでない場合に待機を終了します。
  // 動的コンテンツの読み込み完了を待つ際に有効です。

  // 特定のセレクタが出現するまで待機します
  await page.waitForSelector('.data-container', { timeout: 10000 });

  // ページ内の動的に生成されたデータを抽出します
  const data = await page.evaluate(() => {
    const items = Array.from(document.querySelectorAll('.data-container .item'));
    return items.map(item => item.textContent.trim());
  });

  console.log('抽出されたデータ:', data);

  await browser.close();
}

scrapeDynamicContent();

ポイント:

  • waitUntil: 'networkidle2':ページのネットワーク活動が落ち着くまで待機することで、JavaScriptによる動的コンテンツの読み込みを待ちます。
  • page.waitForSelector():特定の要素がDOMに現れるまで待機します。
  • page.setUserAgent()page.setViewport():ブラウザの識別情報を偽装し、アンチボットシステムの検出を回避するのに役立ちます。
  • puppeteer-extra-plugin-stealth:一般的なボット検出技術を回避するためのプラグインです。これにより、Puppeteerが自動化されたブラウザであると認識されにくくなります。

2. E2Eテストの自動化と視覚的回帰テスト

PuppeteerはWebアプリケーションのE2E(End-to-End)テストにおいて非常に強力です。ユーザーが行う一連の操作をシミュレートし、期待通りの動作をしているかを確認できます。さらに、スクリーンショットを比較することで、UIの予期せぬ変更(視覚的回帰)を検出できます。

import puppeteer from 'puppeteer';
import fs from 'fs';
import path from 'path';

async function runE2ETest() {
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();

  await page.goto('https://your-webapp.com/login', { waitUntil: 'domcontentloaded' });

  // ログインフォームのテスト
  await page.locator('#username').fill('testuser');
  await page.locator('#password').fill('password123');
  await page.locator('#login-button').click();

  // ログイン成功後のページ遷移を待ちます
  await page.waitForNavigation({ waitUntil: 'domcontentloaded' });
  console.log('ログインに成功しました。');

  // ダッシュボードページのスクリーンショットを撮り、視覚的回帰テストに使用します
  const screenshotPath = path.join(process.cwd(), 'screenshots', 'dashboard.png');
  // スクリーンショット保存用のディレクトリが存在しない場合は作成します
  fs.mkdirSync(path.dirname(screenshotPath), { recursive: true });
  await page.screenshot({ path: screenshotPath });
  console.log(`ダッシュボードのスクリーンショットを保存しました: ${screenshotPath}`);

  // 例えば、保存されたスクリーンショットを過去のバージョンと比較するロジックを追加します
  // (ここでは比較ロジックは省略します。pixelmatchなどのライブラリが利用できます)

  // 特定の要素が存在するか確認するアサーション
  const welcomeMessage = await page.locator('.welcome-message').textContent();
  if (welcomeMessage.includes('Welcome, testuser!')) {
    console.log('ウェルカムメッセージが正しく表示されています。');
  } else {
    console.error('ウェルカムメッセージが期待通りではありません。');
    process.exit(1); // テスト失敗
  }

  await browser.close();
  console.log('E2Eテストが完了しました。');
}

runE2ETest().catch(error => {
  console.error('E2Eテスト中にエラーが発生しました:', error);
  process.exit(1);
});

ポイント:

  • JestやMochaとの連携: Puppeteerはテストフレームワークと組み合わせて使用されることが多いです。jest-puppeteerのようなライブラリを使うと、テストのセットアップが簡単になります。
  • page.screenshot() ページの現在の状態を画像として保存し、以前のバージョンと比較することで、UIの意図しない変更を検出するのに役立ちます。
  • アサーション: page.evaluate()page.locator().textContent()などを使って、ページの特定の要素の内容や状態を検証します。

3. WebページからのPDF・画像生成とカスタマイズ

WebページをPDFファイルとして保存したり、特定の要素の画像を生成したりする機能は、レポート作成や請求書発行、SNS投稿用の画像生成など、多岐にわたる用途で活用できます。

import puppeteer from 'puppeteer';
import path from 'path';
import fs from 'fs';

async function generatePdfAndImage() {
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();

  await page.goto('https://developer.chrome.com/docs/puppeteer/api/puppeteer.page.pdf/', { waitUntil: 'networkidle2' });

  // PDF出力用のディレクトリが存在しない場合は作成します
  const outputDir = path.join(process.cwd(), 'output');
  fs.mkdirSync(outputDir, { recursive: true });

  // ページ全体をPDFとして保存します
  await page.pdf({ 
    path: path.join(outputDir, 'puppeteer-api.pdf'), 
    format: 'A4', 
    printBackground: true 
  });
  console.log('PDFファイルを生成しました: puppeteer-api.pdf');

  // 特定の要素のスクリーンショットを撮ります
  // 例えば、ページのヘッダー部分を画像として保存します
  const headerSelector = '.devsite-header'; // Chrome Developersサイトのヘッダーセレクタ
  await page.waitForSelector(headerSelector);
  const headerElement = await page.locator(headerSelector).waitHandle();
  await headerElement.screenshot({ path: path.join(outputDir, 'header.png') });
  console.log('ヘッダーの画像を生成しました: header.png');

  await browser.close();
}

generatePdfAndImage();

ポイント:

  • page.pdf() format(A4, Letterなど)、printBackground(背景画像を含めるか)、marginなどのオプションでPDFの出力を細かく制御できます。
  • elementHandle.screenshot() page.screenshot()とは異なり、特定のDOM要素のみを画像として切り出すことができます。これは、Webサイトの一部を強調したり、特定のUIコンポーネントの画像を生成したりする際に非常に便利です。
  • CSS印刷スタイルシート: Webサイト側で@media printを使ったCSSを定義しておくと、PDF出力時にそのスタイルが適用され、より整形されたドキュメントを生成できます。

他ツールとの組み合わせ

Puppeteerは単体でも強力ですが、他のツールと組み合わせることでその能力をさらに引き出せます。

1. テストフレームワーク (Jest, Mocha)

PuppeteerはE2Eテストの基盤として非常に優れています。JestやMochaといったJavaScriptのテストフレームワークと組み合わせることで、テストコードの構造化、実行、レポート生成が容易になります。

  • Jest-Puppeteer: Jestの環境にPuppeteerを統合するためのライブラリです。ブラウザの起動・停止をJestのテストライフサイクルにフックさせ、テストごとに新しいページインスタンスを自動で提供してくれます。
    • 組み合わせ方: jest-puppeteerをインストールし、Jestの設定ファイルでプリセットとして指定します。テストコード内でpageオブジェクトを直接利用できるようになります。

2. クラウドファンクション (AWS Lambda, Google Cloud Functions)

Puppeteerはサーバーレス環境で実行することも可能です。これにより、必要なときにだけブラウザを起動し、処理が完了したらリソースを解放するといった、効率的なWeb自動化システムを構築できます。

  • 組み合わせ方: Puppeteer(またはpuppeteer-core)と、サーバーレス環境で実行可能なChromiumバイナリ(例: chrome-aws-lambda)をデプロイします。関数がトリガーされると、PuppeteerがChromiumを起動して指定されたタスクを実行します。

3. プロキシサービス (ScrapeOps, Bright Data)

Webスクレイピングを行う際、IPアドレスのブロックやレートリミットは一般的な問題です。プロキシサービスと組み合わせることで、IPアドレスをローテーションし、検出を回避できます。

  • 組み合わせ方: puppeteer.launch()オプションのargsにプロキシサーバーのアドレスとポートを指定します。認証が必要な場合は、page.authenticate()を使用します。

    const browser = await puppeteer.launch({
      args: ['--proxy-server=http://your-proxy-server:port']
    });
    const page = await browser.newPage();
    // 認証が必要な場合
    await page.authenticate({ username: 'user', password: 'password' });
    

4. CI/CDパイプライン (GitHub Actions, GitLab CI)

E2Eテストや視覚的回帰テストをCI/CDパイプラインに組み込むことで、コードの変更がWebアプリケーションに予期せぬ影響を与えていないかを自動で検証できます。

  • 組み合わせ方: CI/CDの設定ファイル(例: .github/workflows/main.yml)に、Node.js環境のセットアップ、Puppeteerのインストール、テストスクリプトの実行ステップを追加します。ヘッドレスモードでの実行が推奨されます。

よくある設定・カスタマイズ

Puppeteerを使用する上で、特定の要件に合わせて動作を調整するための設定やカスタマイズがいくつかあります。

1. puppeteer.launch() オプション

puppeteer.launch()メソッドには、ブラウザの起動方法を細かく制御するための多くのオプションがあります。

  • headless: true(デフォルト)でGUIなし、falseでGUIありでブラウザを起動します。デバッグ時にはfalseに設定すると便利です。
  • args: ブラウザに渡すコマンドライン引数を指定します。例えば、['--no-sandbox']はLinux環境でrootユーザーとして実行する場合に必要になることがあります。
  • executablePath: 使用するChromium/Chromeの実行ファイルのパスを明示的に指定します。puppeteer-coreを使用する場合に特に重要です。
  • timeout: ブラウザの起動を待つ最大ミリ秒数を設定します。デフォルトは30000ms(30秒)です。
  • defaultViewport: 新しいページを開いた際のデフォルトのビューポート(画面サイズ)を設定します。{ width: 1280, height: 720 }のように指定します。

2. ページごとの設定

pageオブジェクトに対しても、様々な設定を適用できます。

  • page.setViewport(): 特定のページに対してビューポートサイズを設定します。
    await page.setViewport({ width: 1366, height: 768 });
    
  • page.setUserAgent(): ページのユーザーエージェント文字列を設定します。これにより、Webサイトが特定のブラウザやデバイスと認識するように偽装できます。
    await page.setUserAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 13_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Mobile/15E148 Safari/604.1');
    
  • page.setDefaultNavigationTimeout(): page.goto()page.waitForNavigation()などのナビゲーション操作のデフォルトタイムアウトを設定します。
    page.setDefaultNavigationTimeout(60000); // 60秒に設定
    

3. リクエストインターセプト

page.setRequestInterception(true)を有効にすることで、ブラウザがWebリソース(画像、CSS、JavaScriptなど)をリクエストするのをフックできます。これにより、不要なリソースの読み込みをブロックしてパフォーマンスを向上させたり、リクエストの内容を改変したりできます。

import puppeteer from 'puppeteer';

async function interceptRequests() {
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();

  // リクエストインターセプトを有効にします
  await page.setRequestInterception(true);

  page.on('request', (request) => {
    // 画像ファイルをブロックして読み込みを高速化します
    if (request.resourceType() === 'image') {
      request.abort();
    } else {
      request.continue();
    }
  });

  await page.goto('https://example.com/', { waitUntil: 'domcontentloaded' });
  console.log('画像なしでページを読み込みました。');

  await browser.close();
}

interceptRequests();

4. エラーハンドリング

Puppeteerスクリプトはネットワークエラー、セレクタのタイムアウト、ブラウザのクラッシュなど、様々なエラーに直面する可能性があります。try...catchブロックを適切に使用し、エラー発生時にブラウザを確実に閉じることで、スクリプトの堅牢性を高めます。

import puppeteer from 'puppeteer';

async function robustScript() {
  let browser;
  try {
    browser = await puppeteer.launch({ headless: true });
    const page = await browser.newPage();

    await page.goto('https://non-existent-url.com/', { timeout: 5000 }); // 存在しないURLにアクセス

    // 他の操作...

  } catch (error) {
    console.error('スクリプト実行中にエラーが発生しました:', error.message);
  } finally {
    if (browser) {
      await browser.close();
      console.log('ブラウザを閉じました。');
    }
  }
}

robustScript();

今日からできる実行プラン

Puppeteerを始めるための3ステップを紹介します。

ステップ1: 環境構築とPuppeteerのインストール

まずは開発環境を整えましょう。

  1. Node.jsのインストール: 公式サイトからNode.jsをダウンロードし、インストールしてください。これにはnpmも含まれています。
  2. 新しいプロジェクトの作成: 任意のディレクトリで新しいNode.jsプロジェクトを作成します。
    mkdir my-puppeteer-project
    cd my-puppeteer-project
    npm init -y
    
  3. Puppeteerのインストール: プロジェクトにPuppeteerをインストールします。
    npm i puppeteer
    

ステップ2: 基本的なスクリプトの作成と実行

Puppeteerが正しく動作するか確認するため、シンプルなスクリプトを作成してみましょう。

  1. スクリプトファイルの作成: プロジェクトのルートにindex.jsというファイルを作成します。
  2. コードの記述: index.jsに以下のコードを記述します。これは、Webサイトを開き、スクリーンショットを撮るだけの簡単なスクリプトです。
    import puppeteer from 'puppeteer';
    
    async function captureScreenshot() {
      const browser = await puppeteer.launch({ headless: true });
      const page = await browser.newPage();
      await page.goto('https://www.google.com/', { waitUntil: 'domcontentloaded' });
      await page.screenshot({ path: 'google.png' });
      await browser.close();
      console.log('google.png を保存しました。');
    }
    
    captureScreenshot();
    
    package.json"type": "module"を追加すると、import構文が利用できます。
    // package.json
    {
      "name": "my-puppeteer-project",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "type": "module", // これを追加
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "keywords": [],
      "author": "",
      "license": "ISC",
      "dependencies": {
        "puppeteer": "^22.0.0"
      }
    }
    
  3. スクリプトの実行: ターミナルで以下のコマンドを実行します。
    node index.js
    
    プロジェクトディレクトリにgoogle.pngというファイルが作成されていれば成功です。

ステップ3: 応用例への挑戦

基本を習得したら、次に紹介した応用例の中から興味のあるものに挑戦してみましょう。

  1. Webスクレイピング: ニュースサイトからヘッドラインを抽出したり、商品情報サイトから価格を取得したりするスクリプトを作成します。page.evaluate()page.waitForSelector()を活用してください。
  2. E2Eテスト: 自身で開発しているWebアプリケーションのログイン機能やフォーム送信機能を自動でテストするスクリプトを書いてみます。Jestなどのテストフレームワークとの連携も検討してみましょう。
  3. PDF/画像生成: お気に入りのブログ記事をPDFとして保存したり、Webサイトの特定セクションの画像を生成したりするスクリプトを試します。

これらのステップを通じて、Puppeteerの強力な機能を体験し、あなたの開発ワークフローにどのように組み込めるかを理解できるでしょう。


参考文献

広告

-AI