0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Python で Playwright アプリをexe化する時のコツ

Posted at

launch_inspector.py というplaywrightを使うアプリをexe化した際にコツがあったので、シェアします。

まずは、exe化するツールのインストール

pip install pyinstaller

ポイントは、自分のPCのchrome.exeを活用すること!! (chromiumを使おうとすると全然うまくいかなかった!!( ノД`)シクシク…)

    async with async_playwright() as p:
        browser = await p.chromium.launch(
            headless=False,
            executable_path="C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",  # 絶対パス
            args=['--disable-blink-features=AutomationControlled']
        )

launch_inspector.py のコード

# launch_inspector.py
import asyncio
import argparse
import sys
from urllib.parse import urlparse
from playwright.async_api import async_playwright

# --- playwright-stealth のインポート試行 ---
try:
    from playwright_stealth import stealth_async
    _STEALTH_AVAILABLE = True
except ImportError:
    _STEALTH_AVAILABLE = False
# --- ここまで ---


# --- ロギング関数 ---
def log_info(msg):
    print(f"INFO: {msg}")


def log_warning(msg):
    print(f"WARNING: {msg}")


def log_error(msg):
    print(f"ERROR: {msg}")


async def launch_browser(target_url: str, use_stealth: bool):
    """
    指定されたURLでブラウザを起動し、Playwright Inspectorを表示します。

    Args:
        target_url: 開くURL
        use_stealth: stealth_async を使用するかどうか
    Returns:
        正常終了時は0、エラー発生時は1
    """
    try:
        async with async_playwright() as p:
            browser = await p.chromium.launch(
                headless=False,
                executable_path="C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",  # 絶対パス
                args=['--disable-blink-features=AutomationControlled']
            )
            context = await browser.new_context(
                viewport={'width': 1280, 'height': 720},
                locale='ja-JP',
                user_agent=(
                    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
                    'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36'
                ),
                timezone_id='Asia/Tokyo',
                java_script_enabled=True,
                extra_http_headers={'Accept-Language': 'ja-JP,ja;q=0.9,en-US;q=0.8,en;q=0.7'}
            )

            if use_stealth and _STEALTH_AVAILABLE:
                await stealth_async(context)
                log_info("Stealth mode enabled.")
            elif use_stealth and not _STEALTH_AVAILABLE:
                log_warning("Stealth mode requested, but library not found.")

            page = await context.new_page()

            try:
                await page.goto(target_url, timeout=60000, wait_until="domcontentloaded")
            except Exception as goto_error:
                log_error(f"Failed to navigate to {target_url}: {goto_error}")
                await browser.close()
                return 1  # エラーコードを返す

            print("-" * 50)
            print(">>> Playwright Inspector を起動します <<<")
            if use_stealth and _STEALTH_AVAILABLE:
                print("(高度なステルスモードが有効です)")
            else:
                print("(基本的なステルス対策のみ有効です)")
            print("Inspectorウィンドウの [Record ▶️] ボタンを押して操作を記録・確認できます。")
            print("記録や確認が終わったら、Inspectorウィンドウを閉じるか、")
            print("   再生ボタン (Resume) ▶️ を押すとスクリプトが終了します。")
            print("-" * 50)

            await page.pause()
            await browser.close()
            log_info("Browser closed.")

    except Exception as e:
        log_error(f"An error occurred: {e}")
        return 1  # エラーコードを返す

    return 0  # 正常終了コードを返す


def is_valid_url(url):
    """
    URLが有効かどうかをチェックします。

    Args:
        url: チェックするURL

    Returns:
        有効なURLの場合はTrue、それ以外はFalse
    """
    try:
        result = urlparse(url)
        return all([result.scheme, result.netloc])
    except:
        return False


def main():
    """
    コマンドライン引数を解析し、ブラウザを起動します。

    Returns:
        正常終了時は0、エラー発生時は1
    """
    parser = argparse.ArgumentParser(
        description="Launch Chromium with Playwright Inspector."
    )
    parser.add_argument(
        "url",
        help="The target URL to open (e.g., https://www.google.com)"
    )
    parser.add_argument(
        "--no-stealth",
        action="store_true",
        help="Disable applying playwright-stealth modifications."
    )

    args = parser.parse_args()

    if not is_valid_url(args.url):
        print("Error: Invalid URL provided.")
        return 1

    use_stealth = not args.no_stealth
    return asyncio.run(launch_browser(args.url, use_stealth))


if __name__ == "__main__":
    sys.exit(main())

以下のコマンドで、launch_inspector.spec を作成する。

pyi-makespec --onefile --console --noupx launch_inspector.py

launch_inspector.spec の内容
以下の通り作成したら、上手くいった。
ポイントは、自分のchromeを使うこと。
# Chromeの実行ファイル
('C:\Program Files\Google\Chrome\Application\chrome.exe', '.'),

# -*- mode: python ; coding: utf-8 -*-

block_cipher = None

a = Analysis(
    ['launch_inspector.py'],
    pathex=[],
    binaries=[],
    datas=[
        # Chromiumの実行ファイル
        ('C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe', '.'),
        # Playwrightのディレクトリ全体
        ('C:\\Users\\sinzy\\playwright-record-scraper3\\venv312\\Lib\\site-packages\\playwright', 'playwright'),
        # Playwrightに必要なその他のデータファイル (必要に応じて追加)
        ('C:\\Users\\sinzy\\playwright-record-scraper3\\venv312\\Lib\\site-packages\\playwright_stealth\\js\\chrome.app.js', 'playwright_stealth\\js'),
        ('C:\\Users\\sinzy\\playwright-record-scraper3\\venv312\\Lib\\site-packages\\playwright_stealth\\js\\chrome.csi.js', 'playwright_stealth\\js'),
        ('C:\\Users\\sinzy\\playwright-record-scraper3\\venv312\\Lib\\site-packages\\playwright_stealth\\js\\chrome.hairline.js', 'playwright_stealth\\js'),
        ('C:\\Users\\sinzy\\playwright-record-scraper3\\venv312\\Lib\\site-packages\\playwright_stealth\\js\\chrome.load.times.js', 'playwright_stealth\\js'),
        ('C:\\Users\\sinzy\\playwright-record-scraper3\\venv312\\Lib\\site-packages\\playwright_stealth\\js\\chrome.runtime.js', 'playwright_stealth\\js'),
        ('C:\\Users\\sinzy\\playwright-record-scraper3\\venv312\\Lib\\site-packages\\playwright_stealth\\js\\generate.magic.arrays.js', 'playwright_stealth\\js'),
        ('C:\\Users\\sinzy\\playwright-record-scraper3\\venv312\\Lib\\site-packages\\playwright_stealth\\js\\iframe.contentWindow.js', 'playwright_stealth\\js'),
        ('C:\\Users\\sinzy\\playwright-record-scraper3\\venv312\\Lib\\site-packages\\playwright_stealth\\js\\media.codecs.js', 'playwright_stealth\\js'),
        ('C:\\Users\\sinzy\\playwright-record-scraper3\\venv312\\Lib\\site-packages\\playwright_stealth\\js\\navigator.hardwareConcurrency.js', 'playwright_stealth\\js'),
        ('C:\\Users\\sinzy\\playwright-record-scraper3\\venv312\\Lib\\site-packages\\playwright_stealth\\js\\navigator.languages.js', 'playwright_stealth\\js'),
        ('C:\\Users\\sinzy\\playwright-record-scraper3\\venv312\\Lib\\site-packages\\playwright_stealth\\js\\navigator.permissions.js', 'playwright_stealth\\js'),
        ('C:\\Users\\sinzy\\playwright-record-scraper3\\venv312\\Lib\\site-packages\\playwright_stealth\\js\\navigator.platform.js', 'playwright_stealth\\js'),
        ('C:\\Users\\sinzy\\playwright-record-scraper3\\venv312\\Lib\\site-packages\\playwright_stealth\\js\\navigator.plugins.js', 'playwright_stealth\\js'),
        ('C:\\Users\\sinzy\\playwright-record-scraper3\\venv312\\Lib\\site-packages\\playwright_stealth\\js\\navigator.userAgent.js', 'playwright_stealth\\js'),
        ('C:\\Users\\sinzy\\playwright-record-scraper3\\venv312\\Lib\\site-packages\\playwright_stealth\\js\\navigator.vendor.js', 'playwright_stealth\\js'),
        ('C:\\Users\\sinzy\\playwright-record-scraper3\\venv312\\Lib\\site-packages\\playwright_stealth\\js\\utils.js', 'playwright_stealth\\js'),
        ('C:\\Users\\sinzy\\playwright-record-scraper3\\venv312\\Lib\\site-packages\\playwright_stealth\\js\\webgl.vendor.js', 'playwright_stealth\\js'),
        ('C:\\Users\\sinzy\\playwright-record-scraper3\\venv312\\Lib\\site-packages\\playwright_stealth\\js\\window.outerdimensions.js', 'playwright_stealth\\js'),

    ],
    hiddenimports=[],
    hookspath=[],  # hookspathを削除
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],
    win_no_prefer_redirects=False,
    win_private_assemblies=False,
    cipher=block_cipher,
    noarchive=False
)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)

exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          [],
          name='launch_inspector',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=False,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True,
          disable_windowed_traceback=False,
          target_arch=None,
          codesign_identity=None,
          entitlements_file=None )

以下のコマンドで、exe化

pyinstaller launch_inspector.spec

これで、成功した!!
セキュリティソフトにも誤検知されなかった!!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?