Under the Snow
ホーム API ステータス About お問い合わせ
ホーム API ステータス About お問い合わせ
  1. ホーム
  2. >
  3. Web開発
  4. >
  5. Linux Mintで狙った位置を確実に撮るPuppeteerスクリーンショットの術

Linux Mintで狙った位置を確実に撮るPuppeteerスクリーンショットの術

2025年9月12日 • 3分で読める
Web開発
Puppeteerスクリーンショット自動化ブックマークレットLinux Mint

導入/背景

ウェブ画面の特定位置を正確にスクリーンショットとして保存したい場面は珍しくありません。UIの差分確認、デザインレビュー、バナーの掲出位置の確認、あるいはサポートのための再現画像作成など、用途は幅広いです。ところが、人手での操作は再現性が低く、ピクセル単位の位置合わせも難しいのが実情です。本稿では、Puppeteerによる自動化と、ブラウザだけで完結する小さな補助ツールを組み合わせ、狙った位置を簡潔に、かつ再現性高く撮影する手順を解説します。日々の運用で役立つ地味な工夫が、後の工数削減に効きます。

技術的な話

Puppeteerとは

PuppeteerはNode.jsでChromeやChromiumブラウザを自動操作するライブラリです。ページを開く、クリック、スクリーンショット撮影などを、プログラムから指示できます。人間の手作業と違って毎回同じ条件で実行できるため、テストや画像生成の自動化でよく使われています。

本節は「コピペでOK」を基本方針とします。以下の順に示します。

  1. HUD表示+クリックでY座標をコピー(ブックマークレット、トグル式)
  2. URLとY座標を指定して撮影するPuppeteerスクリプト(Node.js)

Puppeteerスクリーンショット実行例

こちらは実際にスクリプトを実行し、撮った画像です。

1. HUD表示+クリックでコピー(ブックマークレット、トグル式)

以下をブックマークのURL欄に貼り付けて保存します。ブックマーク実行で左上にHUD(Y/H/VH)が表示され、任意の位置をクリックすると現在のスクロール量(window.scrollY)をコピーします。Shift+クリックで80px差し引き(固定ヘッダー想定)。もう一度ブックマークを押すとHUDと待受けが解除されます。リンク等の既定動作は抑止します。

javascript:(()=>{const M_KEY='__ys_hud_manager__';if(window[M_KEY]){const{hud,onScroll,onResize,onClick}=window[M_KEY];window.removeEventListener('scroll',onScroll);window.removeEventListener('resize',onResize);document.removeEventListener('click',onClick,true);if(hud){hud.remove()};delete window[M_KEY];return};const hud=document.createElement('div');Object.assign(hud.style,{position:'fixed',top:'8px',left:'8px',zIndex:2147483647,padding:'4px 8px',background:'rgba(0,0,0,.75)',color:'#fff',font:'12px/1.4 monospace',borderRadius:'4px',pointerEvents:'none',whiteSpace:'pre'});document.documentElement.appendChild(hud);let lastMsgAt=0;const metrics=()=>%60Y:${Math.round(window.scrollY)} H:${document.documentElement.scrollHeight} VH:${window.innerHeight}%60;const render=()=>{if(Date.now()-lastMsgAt>1200){hud.textContent=metrics()}};const copyText=(t)=>{try{navigator.clipboard.writeText(String(t));hud.textContent=%60Copied Y: ${t}%60}catch(e){prompt('Copy Y:',String(t));hud.textContent=%60Shown in prompt: ${t}%60}lastMsgAt=Date.now();setTimeout(render,1300)};const onScroll=()=>render();const onResize=()=>render();const onClick=(e)=>{e.preventDefault();e.stopPropagation();if(e.stopImmediatePropagation)e.stopImmediatePropagation();const off=e.shiftKey?80:0;const y=Math.round(window.scrollY-off);copyText(y)};window.addEventListener('scroll',onScroll,{passive:true});window.addEventListener('resize',onResize);document.addEventListener('click',onClick,true);render();window[M_KEY]={hud,onScroll,onResize,onClick};})()

安全上の注意/免責

  • ブックマークレットは「開いているページの権限」で動きます。機密情報を含むページ(社内管理画面、銀行、認証中のタブ等)では実行しないでください。
  • 掲載コードは短いので、実行前に必ず全文を自分で確認してください。ブックマークに保存した後も、内容が意図どおりか見直すと安心です。
  • 当スニペットはクリップボードへの書き込みを行います(ブラウザが許可を求める場合があります)。
  • 本コードの利用は自己責任でお願いします。実行によって生じたいかなる損害についても、筆者は責任を負いません。

2. URLとY座標を指定して撮影するPuppeteerスクリプト(Node.js)

次のファイルを shot.js として保存し、npm i puppeteer を行ったディレクトリで実行します。node shot.js <url> <y> [out] の形式で、URLとY座標(px)を指定できます。出力ファイル名を省略すると、YYYYMMDD_HHMMSS_<title>.png で自動命名します。

// shot.js
// shot.js
const puppeteer = require('puppeteer');
const {setTimeout: delay} = require('timers/promises');

// Usage: node shot.js <url> <y> [out]
// - <url>: target URL (required)
// - <y>: scroll position in px (optional)
// - [out]: output filename (optional). If omitted, it becomes
//           YYYYMMDD_HHMMSS_<title>.png based on the page title.

(async () => {
  const argv = process.argv.slice(2);
  if (argv.includes('--help') || argv.includes('-h')) {
    console.log('Usage: node shot.js <url> <y> [out]\n  <url>: target URL (required)\n  <y>: scroll Y in px (optional)\n  [out]: output filename (optional). If omitted, it becomes YYYYMMDD_HHMMSS_<title>.png');
    process.exit(0);
  }

  const urlArg = argv[0];
  const yArg = argv[1] !== undefined ? Number(argv[1]) : undefined;
  const outArg = argv[2];

  if (!urlArg) {
    console.error('URL is required.\nUsage: node shot.js <url> <y> [out]');
    process.exit(1);
  }

  const url = urlArg;
  // outPath will be decided after the page title is available
  let outPath;

  let browser;
  try {
    browser = await puppeteer.launch({
      headless: true,
      args: [
        // CI/コンテナ環境での起動安定化(必要ない環境では無視されます)
        '--no-sandbox',
        '--disable-setuid-sandbox',
      ],
    });

    const page = await browser.newPage();
    await page.setViewport({ width: 1600, height: 1200 });
    await page.goto(url, { waitUntil: 'networkidle2', timeout: 60_000 });

    if (!Number.isNaN(yArg) && yArg !== undefined) {
      // ページの最大スクロール量にクランプしてから移動
      await page.evaluate((y) => {
        const max = Math.max(0, document.documentElement.scrollHeight - window.innerHeight);
        const yy = Math.max(0, Math.min(max, Math.round(y)));
        window.scrollTo(0, yy);
      }, yArg);
    }

    await delay(200);
    // Decide output filename: use arg/ENV or auto-generate: YYYYMMDD_HHMMSS_Title.png
    if (!outPath) {
      const title = (await page.title()) || 'untitled';
      const safeTitle = title
        .replace(/[\n\r\t]/g, ' ')
        .replace(/[\\/:*?"<>|]/g, '')
        .replace(/\s+/g, ' ')
        .trim()
        .replace(/ /g, '_')
        .slice(0, 60);
      const pad = (n) => String(n).padStart(2, '0');
      const d = new Date();
      const name = `${d.getFullYear()}${pad(d.getMonth()+1)}${pad(d.getDate())}_${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}_${safeTitle || 'untitled'}`;
      outPath = outArg || process.env.OUT || `${name}.png`;
    }

    await page.screenshot({ path: outPath, fullPage: false });
    console.log(`Saved: ${outPath}`);
  } catch (err) {
    console.error('shot.js error:', err);
    process.exitCode = 1;
  } finally {
    if (browser) {
      await browser.close();
    }
  }
})();

実行例:

node shot.js https://example.com 1200 example.png

Y座標は前節の手段で取得すると効率が良いです。Puppeteer側では最大スクロール範囲にクランプしてから移動しているため、ページの長さが想定より短い場合でも安全です。

おまけ:ふつうに撮る手順(Linux Mint)

Puppeteerを使わない通常の撮影手順を簡潔にまとめておきます。

  • キーボード

    • PrtScn: 全画面撮影
    • Alt + PrtScn: アクティブウィンドウ
    • Shift + PrtScn: 範囲選択
  • Chrome/Chromium で撮る(DevTools 標準)

    1. F12 または Ctrl+Shift+I で開発者ツールを開く
    2. Ctrl+Shift+P(Run command)→「screenshot」(日本語にしている方はカタカナで)
    3. Full size / Visible / Node から選んで保存
    • ヒント: DevTools を別ウィンドウ(Dock side: undock)にするとページがフル幅のまま撮影できます。
  • コマンドラインから撮る

    • gnome-screenshot(入っていれば)
      gnome-screenshot -d 5 -f ~/Pictures/screenshot.png
      gnome-screenshot -a -d 5 -f ~/Pictures/selected.png
    • Mintの他エディションでよくあるコマンド
      mate-screenshot -d 5 -f ~/Pictures/screenshot.png
      xfce4-screenshooter --fullscreen --delay 5 --save ~/Pictures/xfce4-screenshot.png
      ※ xfce4-screenshooter は —fullscreen / —window / —region のいずれか指定が必須。
  • Chrome/Chromium をヘッドレスで

    google-chrome --headless --disable-gpu --window-size=1600,1200 \
      --screenshot=output.png https://example.com
    chromium --headless --disable-gpu --window-size=1600,1200 \
      --screenshot=output.png https://example.com
    • ブラウザUIやスクロールバーが入らない綺麗なキャプチャ。特定のY位置からの撮影は未対応。
  • 撮影後のトリミング

    • GUI: Pix / GIMP
    • CLI: ImageMagick
      convert screenshot.png -crop 800x600+100+100 cropped.png

設計上のトレードオフ

  • 位置の決め方
    • 固定ピクセル(本稿の<y>)は単純で再現性が高い一方、レスポンシブレイアウトでは崩れに弱いです。
    • 要素基準(CSSセレクタで目的要素へスクロール)に拡張すれば、レイアウト変化に強くなりますが、セレクタの管理コストが増します。
  • 表示の安定化
    • ネットワーク待機をnetworkidle2と短い待機(例: 200ms)で組み合わせて、遅延描画の揺らぎを抑えています。
    • 画像や広告などの外部要素が多いページでは、さらに明示的な待機(特定セレクタのwaitForSelector)が有効です。
  • 実行環境
    • コンテナ/CIでの安定動作のため--no-sandboxを付けています。不要な環境では削除して構いません。

実運用での留意点

  • 画面サイズは要件に合わせて固定(例: 1600x1200)するのが無難です。レビュー文化がある組織では、撮影基準の明文化が効果的です。
  • フォントやレンダリングの差異が差分に影響するため、OSやヘッドレスのバージョンを固定します。
  • 重要なビューはフルページ撮影の併用も検討します。遅延読み込みが強いページでは段階スクロール+複数撮影が安定します。

まとめ

狙った位置のスクリーンショットを再現性高く得るには、位置取得と撮影を分けて設計するのが近道です。ブラウザ側でY座標を素早く取得し、Puppeteerで同一条件のビューポートと待機条件を整えて撮影すれば、手戻りの少ない運用が実現します。小さな自動化の積み重ねが、最終的にはレビュー効率と品質の安定につながります。

ここまでこだわったのは、ただただスクロールバーが入るのが嫌だからという、しょうもない理由が燃料です。特に不揃いなのは好きではなく、4:3の比率は見やすいと思います。美しくあれ。

参考文献

  • https://pptr.dev/ (Puppeteer公式ドキュメント)
  • https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollY (MDN: window.scrollY)
  • https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo (MDN: window.scrollTo)
  • https://nodejs.org/api/timers.html#timerspromises (Node.js: timers/promises)
Under the Snow

この記事をシェア

Twitter Facebook
前の記事 VS Code 1.104 アップデート徹底レビュー:エージェント時代の編集体験へ 次の記事 Cloudflare R2 × Workers × Koyebで低コストなログアーカイブ基盤を設計・実装する実録

関連記事

Astro 5 への実践アップグレード完全ガイド(2025年1月版)

2025年1月15日 Web開発

Python + Docker実践ガイド:マイクロサービス開発からCI/CD構築まで

2024年12月5日 Web開発

Astroの勉強を始めよう

2024年4月1日 Web開発

ステータス

  • Cloudflare 読み込み中…
  • Deno 読み込み中…
  • Docker 読み込み中…
  • GitHub 読み込み中…
  • Koyeb 読み込み中…

カテゴリ

  • AI (10)
  • Cloud (1)
  • Cloudflare (3)
  • DIY・修理 (1)
  • kiroを使い倒せ (5)
  • Linux (4)
  • Tech (7)
  • Web開発 (4)
  • クラウド (3)
  • スマートフォン (2)
  • ツール・ガジェット (1)
  • ライフスタイル (1)
  • 金融 (2)
  • 特別支援教育 (1)
  • 日記 (1)
  • 発達障害と自己理解 (4)

アーカイブ

  • 2025年10月 (15)
  • 2025年9月 (13)
  • 2025年8月 (9)
  • 2025年6月 (1)
  • 2025年5月 (2)
  • 2025年4月 (2)
  • 2025年3月 (2)
  • 2025年1月 (1)
  • 2024年12月 (1)
  • 2024年11月 (1)
  • 2024年7月 (1)
  • 2024年4月 (2)

タグ

Claude AI Kiro Linux Mint Anthropic EIOTCLUB eSIM ベンチマーク 物理eSIM 自動化 Cloudflare Workers MCP Astro リリース コーディング Sonnet エッジコンピューティング Kubernetes 実行機能 ADHD 発達障害 LLM 格安SIM ドコモ povo MNP Linux 楽天モバイル SIM eSIM非対応デバイス AI IDE SaaS 料金モデル Koyeb VS Code Revolut Wise Codex Claude Code

Under the Snow

Astro 5.xとCloudflare Pagesで構築された軽量ブログサイトです。
今日も何かを発信しています。

クイックリンク

ホーム アーカイブ API ステータス このブログについて お問い合わせ クッキー設定

法的情報

プライバシーポリシー 免責事項 利用規約

フォローする

© 2025 Under the Snow. All rights reserved.

Built with Astro + Cloudflare Pages

の検索結果

0件の記事が見つかりました

検索結果が見つかりません

「」に一致する記事がありませんでした。

検索のヒント:

  • キーワードのスペルを確認してください
  • 別のキーワードを試してみてください
  • より一般的な単語を使用してみてください

検索中...

クッキーと広告に関するお願い

当サイトでは、利用体験の向上と広告配信のためにクッキー等を使用する場合があります。 詳細は プライバシーポリシー をご確認ください。