SeleniumをEXEで動かす (python)

記載日：2022/03/11
更新日：2025/03/06 Selenium4対応
Selenium、Web Driver、Browser（Chrome）を１つにまとめたEXEを作りたい機会があったので、忘れないように記載します。
（セキュリティ面を考えるとChromeは最新バージョンに近い方が良いので、EXEはある程度の頻度で更新した方が良いかと思います。）

#### 目標
EXE１つでスクレイピングを実行できるようにすること。
なお作業はWindowsで実施する。
（Pyinstallerはコンバータではないので、Linuxで作業するとEXEを出力できない。）

**[update 2025/03/06]**
Proxyを通るPCだったのですが、selenium4にしたら`504 DNS エラー`が出るようになりました。調べた結果、環境変数no_proxyにlocalhostの設定をすることで動くようになりました。（[参考サイト](https://qiita.com/yu-chan_101/items/f44e8118ec364a1aa0fc)）

#### バージョン情報
**[update 2025/03/06]**
・OS：Windows11
・Python：3.9.6
・pip：25.0.1
・Pyinstaller：6.12.0
・Selenium：4.29.0

~~Selenium3~~
~~・OS：Windows11~~
~~・Python：3.9.6~~
~~・pip：21.1.3~~
~~・Pyinstaller：4.8~~
~~・Selenium：4.1.0~~

#### 流れ
１．Selenium、Pyinstallerのインストール
２．Chromeをプロジェクトの任意のフォルダへコピー。
３．Web Driverをダウンロードし、プロジェクトの任意のフォルダへコピー。
４．PythonでSelenium実行ファイル作成。
５．PyinstallerでEXE生成。

#### プロジェクト構成
　project
　　|
　　|-browser
　　| 　|-99.0.4844.51
　　| 　|-chrome.exe
　　|
　　|-driver
　　| 　|-chromedriver.exe
　　|
　　|-services
　　| 　|-process.py
　　|
　　|-scraper.py
　　|-scraper.spec

#### 作業
０．事前準備
　・WindowsにPython、pipをインストールする。
　　私の場合はpyenv、pipenvもインストールしたので、”python” ”pip”でコマンド実行できましたが、
　　そうでない方は”python3”のようにコマンドが少し異なるかもしれません。

１．Selenium、Pyinstallerのインストール
　・以下コマンドを実行し、SeleniumとPyinstallerをインストールする。
~~~python
pip install selenium
pip install pyinstaller
~~~

２．Chromeをプロジェクトの任意のフォルダへコピー
　・projectフォルダにbrowserフォルダを作成する。
　・browserフォルダにChromeをコピーする。
　　私のPCの場合、”C:\Program Files (x86)\Google\Chrome\Application\”の中の
　　”99.0.4844.51”フォルダと”chrome.exe”をコピーした。

３．Web Driverをダウンロードし、プロジェクトの任意のフォルダへコピー
　・projectフォルダにdriverフォルダを作成する。
　・以下Webサイトからドライバーをダウンロードし、driverフォルダへコピーする。
　　https://chromedriver.chromium.org/downloads

４．PythonでSelenium実行ファイル作成
　・以下のようにSeleniumの実行ファイルを作成する。
~~~python
# scraper.py
import os
import sys
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from services.process import Process

def main():
    BrowserPath=ResourcePath("./browser/chrome.exe") # ブラウザ
    DriverPath=ResourcePath("./driver/chromedriver.exe") # ウェブドライバ

    # ウェブドライバ設定
    options=Options()
    options.binary_location=BrowserPath
    options.add_argument("--headless") # 動きを見たい場合はコメントアウトする。
    service = Service(executable_path=DriverPath) # Selenium4対応
    # driver=webdriver.Chrome(DriverPath, options=options) # Selenium3
    driver = webdriver.Chrome(options=options, service=service) # Selenium4対応

    # スクレイピング
    ProcessC=Process(driver)
    ProcessC.goPage()

    # クローズ処理
    time.sleep(30)
    driver.close()
    driver.quit()

def ResourcePath(relativePath):
    try:
        basePath=sys._MEIPASS
    except Exception:
        basePath=os.path.dirname(__file__)
    return os.path.join(basePath, relativePath)

if __name__=="__main__":
    main()
~~~
~~~python
# process.py
class Process:
    def __init__(self, driver):
        self.driver=driver
    
    def goPage(self):
        self.driver.get("https://[ドメインやIP]/")
~~~

５．PyinstallerでEXE生成
　・以下コマンドを実行し、scraper.specファイルを出力する。
　　オプションをつけずにspecファイルを出力し、後から編集しても良いが少し面倒。
~~~
pyinstaller scraper.py --onefile --noconsole
~~~
　・scraper.specを以下のように編集する。（Analysisのdatasとhiddenimportsを編集。）
~~~text
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['scraper.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='scraper',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=False,
          disable_windowed_traceback=False,
          target_arch=None,
          codesign_identity=None,
          entitlements_file=None )
~~~
　・以下コマンドを実行する。distフォルダが生成し、scraper.exeが生成される。
　　このscraper.exeを実行することでスクレイピングできる。
~~~
pyinstaller scraper.spec
~~~

#### 参考にさせて頂いたサイト
・Pyinstallerでbrowser、driverを含めたEXEを作る
　https://www.zacoding.com/post/python-selenium-pyinstaller/
・.specファイルの書き方（ファイルを含める）
　https://timesaving.hatenablog.com/entry/2021/03/09/160000
・Selenium4にしたら`504 DNS エラー`が出るようになったときの対処（Proxy環境）
　https://qiita.com/yu-chan_101/items/f44e8118ec364a1aa0fc