nprogram’s blog

気ままに、プログラミングのトピックについて書いていきます

seleniumライブラリを含めて、pyinstallerでEXE化する

はじめに

Python環境がインストールされていない状況でも、Seleniumライブラリを含めたEXE化によって動作させる。

環境

プロジェクト構成

プロジェクト構成は以下のとおり。

 project
  |
  |-browser
  |  |-103.0.5060.53
  |  |-chrome.exe
  |
  |-driver
  |  |-chromedriver.exe
  |
  |-main.py
  |-selenium-automation.spec

Pythonライブラリバージョン

使用ライブラリバージョンは以下のとおり。

altgraph==0.17.2
async-generator==1.10
attrs==21.4.0
certifi==2022.6.15
cffi==1.15.0
cryptography==37.0.2
future==0.18.2
h11==0.13.0
idna==3.3
outcome==1.2.0
pefile==2022.5.30
pycparser==2.21
pyinstaller==5.1
pyinstaller-hooks-contrib==2022.7
pyOpenSSL==22.0.0
PySocks==1.7.1
pywin32-ctypes==0.2.0
selenium==4.2.0
sniffio==1.2.0
sortedcontainers==2.4.0
trio==0.21.0
trio-websocket==0.9.2
urllib3==1.26.9
wsproto==1.1.0

手順

  1. 以下のコマンドを実行する。selenium-automation.specファイルが生成される

    • pyinstaller main.py --onefile --noconsole --name selenium-automation
  2. specファイルのAnalysisのdatasとhiddenimportsを編集する

    • datas=[("./browser", "./browser"), ("./driver", "./driver")],
    • hiddenimports=["selenium"],
  3. EXE化コマンドで実行
    • --cleanを必ず指定する。前回ファイルが影響することがある
    • pyinstaller --clean selenium-automation.spec

補足

specファイル

specファイルにおいて、hiddenimportsを指定することでライブラリを同梱できる

sys._MEIPASSとは

https://stackoverflow.com/questions/22472124/what-is-sys-meipass-in-python

Cleanな環境でexeファイルを生成すること

余計なPythonライブラリを含めない。最小限の構成で作成する。仮想環境で一度すべてのPythonライブラリをuninstallしてから作業するとよい

  1. Pythonライブラリ取得]

    • pip freeze > requirement.txt
  2. Pythonライブラリ全削除]

    • pip uninstall -r requirement.txt
  3. 手動のpip installで復旧

    • 1つずつ復旧する

ソースコード

main.pyファイルの内容を以下に記載した。

proxyがある場合は、proxyを通す設定が必要になります。 proxyを通して、実行する場合は以下のコメントを外してください。

    # PROXY_AUTH = '{userid}:{password}'
    # set_proxy_setting(PROXY)
    # options.add_argument(f"--proxy-server={PROXY}")
    # options.add_argument(f"--proxy-auth={PROXY_AUTH}")
# main.py

import os
import sys
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time


def set_proxy_setting(proxy_server: str):
    # スクリプト内で環境変数をセットする
    os.environ["http_proxy"] = proxy_server
    os.environ["https_proxy"] = proxy_server
    os.environ['no_proxy'] = "127.0.0.1,localhost"
    os.environ['NO_PROXY'] = "127.0.0.1,localhost"


def resource_path(relative_path):
    try:
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.dirname(__file__)
    return os.path.join(base_path, relative_path)


def main():

    browser_full_path = resource_path("./browser/chrome.exe")
    chrome_driver_full_path = resource_path("./driver/chromedriver.exe")

    # WebDriver のオプションを設定する
    options = Options()
    options.binary_location = browser_full_path
    options.add_argument("start-maximized")
    options.add_argument("-disable-gpu")
    options.add_argument("--ignore-certificate-errors")

    # Selenium Chrome Proxy の設定
    # PROXY Example : "http://192.168.0.100:8080"
    # PROXY = "http://192.168.0.100:8080"
    # PROXY_AUTH = '{userid}:{password}'
    # set_proxy_setting(PROXY)
    # options.add_argument(f"--proxy-server={PROXY}")
    # options.add_argument(f"--proxy-auth={PROXY_AUTH}")

    driver = webdriver.Chrome(
        executable_path=chrome_driver_full_path, chrome_options=options)

    # スクレイピングを実行する
    URL = "https://stackoverflow.com/"
    driver.get(URL)

    # 3秒ウェイトする
    time.sleep(3)

    driver.close()
    driver.quit()


if __name__ == "__main__":
    main()

specファイル

`selenium-automation.spec'の内容を以下に記載した。

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


block_cipher = None


a = Analysis(
    ['main.py'],
    pathex=[],
    binaries=[],
    datas=[("./browser", "./browser"), ("./driver", "./driver")],
    hiddenimports=["selenium"],
    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='selenium-automation',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    upx_exclude=[],
    runtime_tmpdir=None,
    console=False,
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
)

参考リンク