mcpField
W
webpage-screenshotter

webpage-screenshotter

github.com/rkreddyp生産性2163 回インストール49 週間前に更新
リポジトリ

webpage-screenshotter について

webpage-screenshotter は、Playwright を使って URL の高解像度なページ全体のスクリーンショットを撮るスキルです。読み込み待機方法を設定でき、タイムアウトやネットワーク障害、ブラウザーのクラッシュにも対応します。

主な機能

  1. 01ページ全体のスクリーンショット
  2. 02ページ読み込み待機方法の設定
  3. 03タイムアウトとネットワークエラーへの対応
  4. 04スクリーンショットデータの Base64 エンコード
  5. 05複数 URL の一括撮影

活用シーン

  1. 01ウェブサイトの表示監視
  2. 02ビジュアルリグレッション検査
  3. 03ウェブスクレイピングの視覚的確認
  4. 04ドキュメント作成やページ保存

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/rkreddyp/investrecipes --skill webpage-screenshotter

インストール後、Claude Code で/webpage-screenshotterを入力して読み込まれたか確認します。

詳細

スクリーンショット取得スキル

説明

Playwright をベースとした高解像度のスクリーンショット取得スキルです。画質と信頼性を高める最適化された設定で、任意の URL のページ全体を撮影します。

特長

  • 高解像度のビューポート(1920x1080)
  • ページ全体のスクリーンショットを取得
  • タイムアウトエラーの処理
  • 安定性を高めるためにページを再読み込み
  • スクリーンショットデータを Base64 でエンコード
  • 読み込みに時間がかかるページ向けに、タイムアウトを延長(120 秒)

設定

  • ビューポート:1920x1080 ピクセル
  • デバイススケールファクター:0.5
  • タイムアウト:120 秒
  • 待機方法:domcontentloaded
  • スクリーンショットの種類:ページ全体

待機方法

必要に応じて適切な待機方法を選択してください。

  • domcontentloaded(デフォルト):高速で、HTML の解析完了を待ちます。ほとんどのページに適しています。
  • load:すべてのリソース(画像、スタイルシート)の読み込みを待ちます。より確実ですが、時間がかかります。
  • networkidle:ネットワーク通信が 500ms 間発生しなくなるまで待ちます。動的コンテンツに最適です。

Python の実装

import asyncio
import base64
from playwright.async_api import async_playwright
import playwright._impl._api_types

async def get_screenshot(url):
    """
    Capture a full-page screenshot of a given URL using Playwright.
    
    Args:
        url (str): The URL to capture
        
    Returns:
        str: Base64-encoded screenshot data
    """
    print('in get_screenshot_func_remote', url)

    async with async_playwright() as p:
        browser = await p.chromium.launch()
        page = await browser.new_page(viewport={"width": 1920, "height": 1080, "device_scale_factor": 0.5})
        
        try:
            await page.goto(url, wait_until="domcontentloaded", timeout=120000)
        except playwright._impl._api_types.TimeoutError:
            print(f"TimeoutError: Failed to load {url} within the specified timeout.")
            await asyncio.sleep(2)
        
        # Reload page for stability
        await page.reload(wait_until='domcontentloaded')
        
        # Capture full-page screenshot
        await page.screenshot(path="screenshot.png", full_page=True)
        await browser.close()
        
        # Read and encode screenshot
        data = open("screenshot.png", "rb").read()
        print('screenshot done,', len(data))
        encoded_data = base64.b64encode(data).decode('utf-8')
        base64_image_data = f"data:image/png;base64,{encoded_data}"
        print("Screenshot of size %d bytes" % len(data))
        
        return encoded_data

使用例

import asyncio

# Basic usage
async def main():
    url = "https://example.com"
    screenshot_data = await get_screenshot(url)
    print(f"Screenshot captured and encoded: {len(screenshot_data)} characters")

# Run the async function
asyncio.run(main())

高度な使用方法

カスタムパスへの保存
async def get_screenshot_custom_path(url, output_path="screenshot.png"):
    """
    Capture screenshot with custom output path.
    """
    print('in get_screenshot_func_remote', url)

    async with async_playwright() as p:
        browser = await p.chromium.launch()
        page = await browser.new_page(viewport={"width": 1920, "height": 1080, "device_scale_factor": 0.5})
        
        try:
            await page.goto(url, wait_until="domcontentloaded", timeout=120000)
        except playwright._impl._api_types.TimeoutError:
            print(f"TimeoutError: Failed to load {url} within the specified timeout.")
            await asyncio.sleep(2)
        
        await page.reload(wait_until='domcontentloaded')
        await page.screenshot(path=output_path, full_page=True)
        await browser.close()
        
        data = open(output_path, "rb").read()
        print('screenshot done,', len(data))
        encoded_data = base64.b64encode(data).decode('utf-8')
        print("Screenshot of size %d bytes" % len(data))
        
        return encoded_data
複数ページのスクリーンショットを取得
async def capture_multiple_screenshots(urls):
    """
    Capture screenshots of multiple URLs.
    
    Args:
        urls (list): List of URLs to capture
        
    Returns:
        dict: Dictionary mapping URLs to their base64-encoded screenshots
    """
    results = {}
    
    for url in urls:
        try:
            screenshot_data = await get_screenshot(url)
            results[url] = screenshot_data
        except Exception as e:
            print(f"Error capturing {url}: {e}")
            results[url] = None
    
    return results

# Usage
urls = ["https://example.com", "https://another-site.com"]
results = asyncio.run(capture_multiple_screenshots(urls))
ページ全体の読み込みを待機
async def get_screenshot_full_load(url):
    """Wait for all resources to load before screenshot."""
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        page = await browser.new_page(viewport={"width": 1920, "height": 1080, "device_scale_factor": 0.5})
        
        # Wait for complete load including all resources
        await page.goto(url, wait_until="load", timeout=120000)
        
        await page.screenshot(path="screenshot.png", full_page=True)
        await browser.close()
        
        data = open("screenshot.png", "rb").read()
        return base64.b64encode(data).decode('utf-8')
ネットワーク通信がアイドル状態になるまで待機(動的コンテンツ)
async def get_screenshot_network_idle(url):
    """Wait for network to be idle - best for JavaScript-heavy sites."""
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        page = await browser.new_page(viewport={"width": 1920, "height": 1080, "device_scale_factor": 0.5})
        
        # Wait for network idle (no requests for 500ms)
        await page.goto(url, wait_until="networkidle", timeout=120000)
        
        # Optional: wait for specific element
        await page.wait_for_selector("body", state="visible")
        
        await page.screenshot(path="screenshot.png", full_page=True)
        await browser.close()
        
        data = open("screenshot.png", "rb").read()
        return base64.b64encode(data).decode('utf-8')

Cloudflare の回避

Cloudflare によって保護されたサイトでは、標準的な Playwright セッションは検出されることがよくあります。検出を回避するには、次の手法を使用してください。

インストール

Node.js(JavaScript):

npm install playwright-extra playwright-extra-plugin-stealth

Python:

pip install playwright playwright-stealth
ステルスモードの設定(JavaScript)
const { chromium } = require('playwright-extra');
const stealth = require('puppeteer-extra-plugin-stealth')();

// CRITICAL: Must use stealth plugin BEFORE launching browser
chromium.use(stealth);

// Launch with stealth enabled
const browser = await chromium.launch({ 
  headless: false // Headed mode reduces detection
});
ブラウザーのフィンガープリントのランダム化

フィンガープリンティングを避けるため、ビューポート、ユーザーエージェント、ロケール、タイムゾーンをランダム化します。

const context = await browser.newContext({
  viewport: {
    width: 1280 + Math.floor(Math.random() * 100), // Randomize
    height: 720 + Math.floor(Math.random() * 100)
  },
  userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
  locale: 'en-US',
  timezoneId: 'America/New_York'
});
セッションの永続化

Cookie と localStorage を再利用し、再訪問ユーザーとして認識されるようにします。

const userDataDir = './session-profile';

const browser = await chromium.launchPersistentContext(userDataDir, {
  headless: false,
  args: ['--start-maximized']
});
プロキシのローテーション

リクエストを分散し、IP アドレスに基づくブロックを避けるためにプロキシを切り替えます。

const browser = await chromium.launch({
  headless: false,
  args: [
    '--proxy-server=http://username:password@proxy-ip:port'
  ]
});
CAPTCHA の検出
// Check for CAPTCHA iframe
const isCaptchaPresent = await page.$('iframe[src*="captcha"]');

if (isCaptchaPresent) {
  console.log('CAPTCHA detected – solve or switch proxy');
}
CAPTCHA の解決(任意)

reCAPTCHA には、2Captcha サービスを使用します。

const RecaptchaPlugin = require('@extra/recaptcha');

chromium.use(
  RecaptchaPlugin({
    provider: {
      id: '2captcha',
      token: 'YOUR_2CAPTCHA_API_KEY'
    },
    visualFeedback: true
  })
);

await page.solveRecaptchas();
セッション Cookie の管理

セッションを維持するために Cookie を保存して復元します。

// Save cookies after successful scrape
const cookies = await context.cookies();
fs.writeFileSync('./cookies.json', JSON.stringify(cookies, null, 2));

// Restore cookies on next run
const savedCookies = JSON.parse(fs.readFileSync('./cookies.json'));
await context.addCookies(savedCookies);
Cloudflare を回避する完全な例
const { chromium } = require('playwright-extra');
const stealth = require('puppeteer-extra-plugin-stealth')();
const fs = require('fs');

chromium.use(stealth);

async function screenshotWithCloudflareBypass(url, proxy = null) {
  const args = proxy ? [`--proxy-server=${proxy}`] : [];
  
  const browser = await chromium.launch({
    headless: false,
    args: args
  });

  const context = await browser.newContext({
    viewport: {
      width: 1280 + Math.floor(Math.random() * 100),
      height: 720 + Math.floor(Math.random() * 100)
    },
    userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    locale: 'en-US',
    timezoneId: 'America/New_York'
  });

  const page = await context.newPage();

  // Load page and wait for Cloudflare checks
  await page.goto(url, { waitUntil: "domcontentloaded" });
  await page.waitForTimeout(5000); // Let Cloudflare finish background checks

  // Check for CAPTCHA
  const captchaPresent = await page.$('iframe[src*="captcha"]');
  if (captchaPresent) {
    console.log('CAPTCHA detected');
    // Handle CAPTCHA or switch proxy
  }

  // Capture screenshot
  await page.screenshot({ path: "screenshot.png", fullPage: true });

  // Save cookies for next visit
  const cookies = await context.cookies();
  fs.writeFileSync('./cookies.json', JSON.stringify(cookies, null, 2));

  await browser.close();
}
ベストプラクティス
  1. ヘッドありモードを使用する(headless: false)— 検出されにくくなります
  2. プロキシをローテーションする — IP アドレスに基づくブロックを避けます
  3. フィンガープリントをランダム化する — ビューポート、ユーザーエージェント、タイムゾーンを変更します
  4. セッションを永続化する — Cookie を再利用し、再訪問ユーザーとして認識されるようにします
  5. Cloudflare の処理を待つ — バックグラウンドの JavaScript チェックに備えて遅延を追加します
  6. CAPTCHA を監視する — チャレンジを検出して処理します
  7. 再利用を制限する — 同じプロキシとユーザーエージェントの組み合わせを頻繁に使い回さないでください

依存関係

Python:

pip install playwright
playwright install chromium

Node.js(Cloudflare 回避機能あり):

npm install playwright-extra playwright-extra-plugin-stealth

エラー処理

このスキルには、次のような堅牢なエラー処理が含まれています。

  • タイムアウトエラー:120 秒以内に読み込まれないページを適切に処理します
  • ネットワーク障害:最初のページ読み込みに失敗しても実行を継続します
  • ブラウザーのクラッシュ:エラー発生時もブラウザーを確実に終了します

パフォーマンスに関する注意

  • ビューポートは 1920x1080、デバイススケールファクターは 0.5 に設定されるため、実効解像度は 960x540 です
  • 非常に長いページでは、ページ全体のスクリーンショット取得に時間がかかることがあります
  • ページの再読み込みにより、動的コンテンツが確実に読み込まれます
  • スクリーンショットは一時的に PNG ファイルとして保存された後、Base64 にエンコードされます

使用例

  • Web サイトの自動監視
  • ビジュアルリグレッションテスト
  • 視覚的な確認を伴う Web スクレイピング
  • ドキュメントの生成
  • Web ページのアーカイブ
  • 品質保証のワークフロー

コメント