puppeteer-automation
Puppeteerを使ったブラウザ自動化に関する専門的なガイダンスを提供するスキルで、ヘッドレスChromeでのWebスクレイピング、テスト、スクリーンショット撮影、JavaScript実行のベストプラクティスをカバーします。
description の原文を見る
Expert guidance for browser automation using Puppeteer with best practices for web scraping, testing, screenshot capture, and JavaScript execution in headless Chrome.
SKILL.md 本文
Puppeteer ブラウザオートメーション
Puppeteer、Node.js ブラウザオートメーション、ウェブスクレイピング、Chrome と Chromium ブラウザの信頼性の高いオートメーションスクリプト構築の専門家です。
コアスキル
- Puppeteer API とブラウザオートメーションパターン
- ページナビゲーションとインタラクション
- 要素選択と操作
- スクリーンショットと PDF 生成
- ネットワークリクエストのインターセプション
- ヘッドレスおよびヘッドフルブラウザモード
- パフォーマンス最適化とメモリ管理
- テストフレームワーク (Jest, Mocha) との統合
キー原則
- 可読性を高めるため、async/await ベースのクリーンなコードを記述
- try/catch ブロックで適切なエラーハンドリングを実装
- 動的コンテンツに対応した堅牢な待機戦略を実装
- メモリリークを防ぐため、ブラウザインスタンスを適切にクローズ
- 再利用可能なオートメーションコードのための モジュール設計パターンに従う
- ブラウザコンテキストとページのライフサイクルを適切に処理
プロジェクトセットアップ
npm init -y
npm install puppeteer
基本構成
const puppeteer = require('puppeteer');
async function main() {
const browser = await puppeteer.launch({
headless: 'new',
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
try {
const page = await browser.newPage();
await page.goto('https://example.com');
// オートメーションコードをここに記述
} finally {
await browser.close();
}
}
main().catch(console.error);
ブラウザ起動オプション
const browser = await puppeteer.launch({
headless: 'new', // 新しいヘッドレスモード、false でブラウザ表示
slowMo: 50, // デバッグ用に動作を遅延
devtools: true, // DevTools を自動オープン
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-accelerated-2d-canvas',
'--disable-gpu',
'--window-size=1920,1080'
],
defaultViewport: {
width: 1920,
height: 1080
}
});
ページナビゲーション
// URL にナビゲート
await page.goto('https://example.com', {
waitUntil: 'networkidle2', // ネットワークがアイドル状態になるまで待機
timeout: 30000
});
// 待機オプション:
// - 'load': load イベントを待機
// - 'domcontentloaded': DOMContentLoaded イベントを待機
// - 'networkidle0': 500ms 間ネットワーク接続がない状態
// - 'networkidle2': 500ms 間ネットワーク接続が 2 つ以下の状態
// 戻る/進む
await page.goBack();
await page.goForward();
// ページをリロード
await page.reload({ waitUntil: 'networkidle2' });
要素選択
クエリセレクタ
// 単一要素
const element = await page.$('selector');
// 複数要素
const elements = await page.$$('selector');
// 要素待機
const element = await page.waitForSelector('selector', {
visible: true,
timeout: 5000
});
// XPath 選択
const elements = await page.$x('//xpath/expression');
ページコンテキスト内での評価
// テキストコンテンツを取得
const text = await page.$eval('selector', el => el.textContent);
// 属性を取得
const href = await page.$eval('a', el => el.getAttribute('href'));
// 複数要素
const texts = await page.$$eval('.items', elements =>
elements.map(el => el.textContent)
);
// 任意の JavaScript を実行
const result = await page.evaluate(() => {
return document.title;
});
ページインタラクション
クリック
await page.click('button#submit');
// オプション付きクリック
await page.click('button', {
button: 'left', // 'left', 'right', 'middle'
clickCount: 1,
delay: 100 // mousedown と mouseup 間の時間
});
// クリックしてナビゲーション待機
await Promise.all([
page.waitForNavigation(),
page.click('a.nav-link')
]);
テキスト入力
// テキスト入力
await page.type('input#username', 'myuser', { delay: 50 });
// クリアして入力
await page.click('input#username', { clickCount: 3 });
await page.type('input#username', 'newvalue');
// キー押下
await page.keyboard.press('Enter');
await page.keyboard.down('Shift');
await page.keyboard.press('Tab');
await page.keyboard.up('Shift');
フォーム処理
// ドロップダウン選択
await page.select('select#country', 'us');
// チェックボックス確認
await page.click('input[type="checkbox"]');
// ファイルアップロード
const inputFile = await page.$('input[type="file"]');
await inputFile.uploadFile('/path/to/file.pdf');
待機戦略
// セレクタ待機
await page.waitForSelector('.loaded');
// セレクタが消えるまで待機
await page.waitForSelector('.loading', { hidden: true });
// 関数条件を待機
await page.waitForFunction(
() => document.querySelector('.count').textContent === '10'
);
// ナビゲーション待機
await page.waitForNavigation({ waitUntil: 'networkidle2' });
// ネットワークリクエスト待機
await page.waitForRequest(request =>
request.url().includes('/api/data')
);
// ネットワークレスポンス待機
await page.waitForResponse(response =>
response.url().includes('/api/data') && response.status() === 200
);
// 固定タイムアウト (控えめに使用)
await page.waitForTimeout(1000);
スクリーンショットと PDF
スクリーンショット
// ページ全体のスクリーンショット
await page.screenshot({
path: 'screenshot.png',
fullPage: true
});
// 要素スクリーンショット
const element = await page.$('.chart');
await element.screenshot({ path: 'chart.png' });
// スクリーンショットオプション
await page.screenshot({
path: 'screenshot.png',
type: 'png', // 'png' または 'jpeg'
quality: 80, // jpeg のみ、0-100
clip: {
x: 0,
y: 0,
width: 800,
height: 600
}
});
PDF 生成
await page.pdf({
path: 'document.pdf',
format: 'A4',
printBackground: true,
margin: {
top: '20px',
right: '20px',
bottom: '20px',
left: '20px'
}
});
ネットワークインターセプション
// リクエストインターセプションを有効化
await page.setRequestInterception(true);
page.on('request', request => {
// 画像とスタイルシートをブロック
if (['image', 'stylesheet'].includes(request.resourceType())) {
request.abort();
} else {
request.continue();
}
});
// リクエスト修正
page.on('request', request => {
request.continue({
headers: {
...request.headers(),
'X-Custom-Header': 'value'
}
});
});
// レスポンス監視
page.on('response', async response => {
if (response.url().includes('/api/')) {
const data = await response.json();
console.log('API Response:', data);
}
});
認証とクッキー
// Basic HTTP 認証
await page.authenticate({
username: 'user',
password: 'pass'
});
// クッキー設定
await page.setCookie({
name: 'session',
value: 'abc123',
domain: 'example.com'
});
// クッキー取得
const cookies = await page.cookies();
// クッキー削除
await page.deleteCookie({ name: 'session' });
ブラウザコンテキストと複数ページ
// シークレットコンテキスト作成
const context = await browser.createIncognitoBrowserContext();
const page = await context.newPage();
// 複数ページ
const page1 = await browser.newPage();
const page2 = await browser.newPage();
// すべてのページを取得
const pages = await browser.pages();
// ポップアップハンドリング
page.on('popup', async popup => {
await popup.waitForLoadState();
console.log('Popup URL:', popup.url());
});
エラーハンドリング
async function scrapeWithRetry(url, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const browser = await puppeteer.launch();
const page = await browser.newPage();
// タイムアウト設定
page.setDefaultTimeout(30000);
await page.goto(url, { waitUntil: 'networkidle2' });
const data = await page.$eval('.content', el => el.textContent);
await browser.close();
return data;
} catch (error) {
console.error(`Attempt ${i + 1} failed:`, error.message);
if (i === maxRetries - 1) throw error;
await new Promise(r => setTimeout(r, 2000 * (i + 1)));
}
}
}
パフォーマンス最適化
// 不要な機能を無効化
await page.setRequestInterception(true);
page.on('request', request => {
const blockedTypes = ['image', 'stylesheet', 'font'];
if (blockedTypes.includes(request.resourceType())) {
request.abort();
} else {
request.continue();
}
});
// ブラウザインスタンスを再利用
const browser = await puppeteer.launch();
async function scrape(url) {
const page = await browser.newPage();
try {
await page.goto(url);
// ... スクレイピングロジック
} finally {
await page.close(); // ブラウザではなくページをクローズ
}
}
// 並列スクレイピング用コネクションプール
const cluster = require('puppeteer-cluster');
主要依存関係
- puppeteer
- puppeteer-core (カスタム Chrome インストール用)
- puppeteer-cluster (並列スクレイピング用)
- puppeteer-extra (プラグイン用)
- puppeteer-extra-plugin-stealth (アンチボット対策)
ベストプラクティス
- 常に finally ブロックでブラウザインスタンスをクローズ
- 要素操作前に
waitForSelectorを使用 networkidle0よりnetworkidle2を優先 (高速化)- アンチボット対策にステルスプラグインを使用
- 適切なエラーハンドリングとリトライを実装
- 長時間実行スクリプトのメモリ使用量を監視
- 分離されたセッション用にブラウザコンテキストを使用
- すべての操作に合理的なタイムアウトを設定
ライセンス: Apache-2.0(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- mindrally
- リポジトリ
- mindrally/skills
- ライセンス
- Apache-2.0
- 最終更新
- 不明
Source: https://github.com/mindrally/skills / ライセンス: Apache-2.0
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。