---
slug: "raspberry-pi-signage-playwright-chromium-kiosk"
title: "Raspberry Pi のサイネージ化 … Playwright で Chromium を最大化して自動操作する"
description: "Raspberry Pi をサイネージ端末として使い、Playwright (Python) + Chromium の --kiosk モードで Web ページを常時フルスクリーン表示する方法。Cookie 永続化による自動認証、.desktop ファイルによる自動起動、scp デプロイまで。"
url: "https://www.ytyng.com/blog/raspberry-pi-signage-playwright-chromium-kiosk"
publish_date: "2026-02-18T03:00:00Z"
created: "2026-02-18T00:17:14.650Z"
updated: "2026-02-27T10:29:36.411Z"
categories: []
keywords: ""
featured_image_url: "https://media.ytyng.com/resize/20260226/139fba997e1e472497fa00d7b1927c84.png.webp?width=768"
has_video: true
has_music: true
video_urls: ["https://media.ytyng.net/ytyng-blog/335/featured-video-1.mp4", "https://media.ytyng.net/ytyng-blog/335/featured-video-2.mp4", "https://media.ytyng.net/ytyng-blog/335/featured-video-3.mp4"]
music_urls: ["https://media.ytyng.net/ytyng-blog/335/featured-music-335-2.mp3", "https://media.ytyng.net/ytyng-blog/335/featured-music-335-3.mp3"]
lang: "ja"
---

# Raspberry Pi のサイネージ化 … Playwright で Chromium を最大化して自動操作する

## 概要

Raspberry Pi を「サイネージ端末」として使い、社内の Web アプリケーションを常時フルスクリーン表示する仕組みを構築した。

ブラウザの自動操作には **Playwright** (Python) を使用し、Chromium の `--kiosk` モードでフルスクリーン表示を実現している。

### この仕組みでできること

- Raspberry Pi 起動時に、自動的に Chromium が開き、指定した Web ページがフルスクリーンで表示される
- ログインが必要なページでも、自動で認証を行う
- Cookie を永続化し、再起動後もログイン状態を維持する
- 開発時は `--no-fullscreen` オプションでウインドウモードに切り替え可能

## 環境

- Raspberry Pi 5 / Raspberry Pi OS (Debian bookworm)
- Python 3.13
- [uv](https://docs.astral.sh/uv/) (Python パッケージマネージャ)
- [Playwright](https://playwright.dev/python/)

## セットアップ

### uv のインストール

```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```

### プロジェクトの依存関係

`pyproject.toml`:

```toml
[project]
name = "rpi-signage"
version = "0.1.0"
description = "Automated Web page launcher for Raspberry Pi using Playwright"
requires-python = "==3.13.*"
dependencies = [
    "playwright>=1.57.0",
    "python-dotenv>=1.2.1",
]
```

### Playwright と Chromium のインストール

```bash
uv sync
uv run playwright install chromium
```

`playwright install chromium` で、Playwright がブラウザを自動操作するために必要な Chromium バイナリがダウンロードされる。Raspberry Pi OS にプリインストールされている Chromium とは別のもの。

ただし、OS にインストール済みの Chromium がある場合はそちらを優先して使う (後述の `get_browser_channel()`)。

## Python コード

### メインスクリプト

```python
#!/usr/bin/env python3

import argparse
import json
import shutil
import time
from pathlib import Path

import dotenv
from playwright._impl._errors import TargetClosedError
from playwright.sync_api import BrowserContext, sync_playwright

COOKIES_FILE = Path(__file__).parent / "cookies.json"


def save_cookies(context: BrowserContext):
    """Cookie を JSON ファイルに保存する"""
    try:
        cookies = context.cookies()
        COOKIES_FILE.write_text(json.dumps(cookies, ensure_ascii=False))
        print(f"Saved {len(cookies)} cookies.")
    except Exception as e:
        print(f"Failed to save cookies: {e}")


def load_cookies(context: BrowserContext):
    """保存済みの Cookie を読み込んでブラウザコンテキストに適用する"""
    if not COOKIES_FILE.exists():
        return
    try:
        cookies = json.loads(COOKIES_FILE.read_text())
        context.add_cookies(cookies)
        print(f"Loaded {len(cookies)} cookies.")
    except Exception as e:
        print(f"Failed to load cookies: {e}")


def get_browser_channel() -> str | None:
    """OS にインストールされた Chromium/Chrome を検出する。
    なければ None を返し、Playwright バンドル版を使用する。"""
    if shutil.which("chromium") or shutil.which("chromium-browser"):
        return "chromium"
    if shutil.which("google-chrome") or shutil.which("chrome"):
        return "chrome"
    return None


def main(args):
    with sync_playwright() as p:
        channel = get_browser_channel()
        chromium_args = [
            "--window-size=1920,1040",
            "--window-position=0,0",
        ]
        if not args.no_fullscreen:
            chromium_args.append("--kiosk")

        context = p.chromium.launch_persistent_context(
            user_data_dir="./browser_data",
            headless=False,
            channel=channel,
            args=chromium_args,
            no_viewport=True,
            ignore_https_errors=True,
        )
        page = context.pages[0] if context.pages else context.new_page()
        load_cookies(context)

        page.goto("https://your-webapp.example.com/")
        time.sleep(2)

        # ログインページにリダイレクトされた場合の認証処理
        if page.locator("#username").count() > 0:
            print("Logging in...")
            page.fill("#username", dotenv.get_key(".env", "USERNAME"))
            page.fill("#password", dotenv.get_key(".env", "PASSWORD"))
            page.click("button[type='submit']")
            time.sleep(3)
            save_cookies(context)

        # Ctrl+C で終了するまで無限待機
        print("Press Ctrl+C to exit.")
        try:
            while True:
                time.sleep(2)
        except KeyboardInterrupt:
            save_cookies(context)
        except TargetClosedError:
            print("Browser window was closed.")

        context.close()


if __name__ == "__main__":
    arg_parser = argparse.ArgumentParser()
    arg_parser.add_argument(
        "--no-fullscreen",
        action="store_true",
        help="フルスクリーンにしない。開発時に指定する。",
    )
    args = arg_parser.parse_args()
    main(args)
```

### コードのポイント

#### `launch_persistent_context`

Playwright の通常の `launch()` ではなく `launch_persistent_context()` を使っている。
`user_data_dir` にブラウザのプロファイルデータ (キャッシュ、ローカルストレージなど) が永続化される。

#### Cookie の永続化

`save_cookies()` / `load_cookies()` で、Cookie を JSON ファイルに保存・復元する。
`launch_persistent_context` でもある程度セッションは維持されるが、明示的に Cookie を保存することで確実にログイン状態を復元できる。

#### `get_browser_channel()`

Raspberry Pi OS には `chromium-browser` がプリインストールされている場合がある。
`shutil.which()` でシステムにインストールされた Chromium / Chrome を検出し、あればそれを使う。なければ Playwright バンドル版の Chromium を使用する。

OS ネイティブの Chromium の方が、Raspberry Pi 上でのパフォーマンスが良い傾向にある。

#### `no_viewport=True`

Playwright はデフォルトでビューポートサイズを固定する。`no_viewport=True` を指定すると、ウインドウサイズに応じてビューポートが動的に変わるようになる。サイネージ用途では画面全体を使いたいのでこの設定が必要。

#### `.env` からの認証情報読み込み

パスワードなどの認証情報は `.env` ファイルに記載し、`python-dotenv` で読み込む。

```
USERNAME=your-username
PASSWORD=your-password
```

## フルスクリーン化の試行錯誤

Raspberry Pi 上で Chromium をフルスクリーン表示するために、いくつかの方法を試した。

### 失敗した方法

#### 1. `xdotool key F11`

シェルスクリプトから遅延実行で F11 キーを送る方法。

```bash
sleep 10 && xdotool key F11 &
```

タイミングの問題で安定しなかった。ブラウザが完全に起動する前に送信されたり、フォーカスが合わなかったりする。

#### 2. `--start-maximized`

Chromium の起動オプション。ウインドウは最大化されるが、アドレスバーやタブバーは残る。サイネージ用途には不十分。

#### 3. JavaScript `requestFullscreen()`

Playwright から JavaScript を実行してフルスクリーンにする方法。

```python
page.evaluate("document.documentElement.requestFullscreen()")
```

ユーザーのジェスチャー (クリックなど) を伴わないプログラム的な呼び出しは、ブラウザのセキュリティポリシーによりブロックされる場合がある。

### 採用した方法: `--kiosk`

```python
chromium_args.append("--kiosk")
```

Chromium の `--kiosk` フラグは、アドレスバー・タブバーを含むすべての UI 要素を非表示にし、完全なフルスクリーンでページを表示する。

キオスク端末 (公共の端末) 用に設計されたモードで、サイネージ用途にも最適。

開発時は `--no-fullscreen` オプションを付けることで `--kiosk` を無効にし、通常のウインドウモードで動作確認できる。

```bash
# 通常起動 (キオスクモード)
uv run ./open_signage.py

# 開発時 (ウインドウモード)
uv run ./open_signage.py --no-fullscreen
```

## デスクトップ自動起動の設定

### シェルスクリプト

自動起動時に実行するシェルスクリプト:

```bash
#!/usr/bin/env bash
set -e
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Starting signage"
cd "$(dirname "$0")"
export DISPLAY=:0
/home/pi/.local/bin/uv run ./open_signage.py
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Signage finished"
```

`export DISPLAY=:0` は、GUI のない autostart 環境から X Window System にアクセスするために必要。

### `.desktop` ファイル

`~/.config/autostart/` に `.desktop` ファイルを配置することで、Raspberry Pi のデスクトップ起動時に自動的にスクリプトが実行される。

```ini
[Desktop Entry]
Type=Application
Name=Web Signage
Exec=/bin/bash -c "/home/pi/signage/autostart.sh >> /tmp/signage.log 2>&1"
Terminal=false
X-GNOME-Autostart-enabled=true
```

ログを `/tmp/signage.log` にリダイレクトしているので、問題が発生した場合はこのファイルを確認する。

## Mac からラズパイへのデプロイ

`scp` でファイルを転送するシンプルなデプロイスクリプト:

```bash
#!/usr/bin/env zsh
set -e
cd "$(dirname "$0")"

FILES=(
  autostart.sh
  open_signage.py
  .env
  pyproject.toml
)

for FILE in "${FILES[@]}"; do
  scp "$FILE" pi@rpi-signage.local:~/signage/
done

scp signage.desktop pi@rpi-signage.local:~/.config/autostart/signage.desktop
```

デプロイ後、ラズパイを再起動すれば新しいスクリプトが自動起動される。

ラズパイ側で初回のみ以下を実行しておく:

```bash
mkdir -p ~/signage
mkdir -p ~/.config/autostart
cd ~/signage
uv sync
uv run playwright install chromium
```

## まとめ

- Playwright + Python で Chromium を自動操作し、サイネージ端末を構築した
- `--kiosk` フラグが Chromium のフルスクリーン化には最も確実
- Cookie の永続化により、認証が必要なページも自動ログインできる
- `.desktop` ファイルで OS 起動時に自動起動
- `uv` でシンプルに依存関係を管理
- `scp` ベースのデプロイスクリプトで Mac からラズパイに簡単にデプロイ
