Make Python & Selenium program executable (.exe) (How to include webdriver in .exe)

Published:  

python selenium


Make a program created with Python & Selenium into an executable format (.exe).
In particular, this time we will make one exe file.
It is easy to use PyInstaller, but as it is, WebDriver (in this article, chromedriver.exe) is not included in the exe. The fact that it is not included in the exe means that when you distribute the executable file, you must also distribute the WebDriver. I didn’t like this, so I investigated how to put it in an exe.

Execution environment

  • Windows 10
  • ChromeDriver 76.0.3809.68
  • Python 3.6.2
  • selenium 3.141.0
  • PyInstaller 3.5

Make it executable with PyInstaller

The basic usage of PyInstaller is explained on the following page:

There are two things to keep in mind when using PyInstaller:

  1. Specifying PyInstaller options
  2. Specifying the path in the source

Specifying PyInstaller options

The following folder structure is assumed:

MyProj/
 ├ driver/
 │ └ chromedriver.exe
 └ main.py

It is made executable by PyInstaller, but with --add-binary as an option. This is specified when you want to include a binary file other than Python (this time chromedriver.exe) in the exe.

Use the following command (replace each path):

pyinstaller ./main.py --onefile --noconsole --add-binary "./driver/chromedriver.exe;./driver"
  • --onefile It outputs as one exe.
  • --noconsole The console is not displayed when the created exe is executed.
  • --add-binary Specify the binary file you want to add to the exe. The specification method is "source_file_path; destination_file_path".

The method of specifying the --add-binary option is a little confusing, but first it is easier to understand if you build without the --onefile option. If you build without the --onefile option, it will be output in multiple files.
For example:

dist/
 └ main/
   ├ driver/
   │ └ chromedriver.exe
   └ main.exe
(* Actually there are many other folders and files.)

You can do the same thing by writing it in the spec file without specifying it as a command line option.

a = Analysis(...
         binaries=[ ( './driver/chromedriver.exe', './driver' ) ],
         ...

The spec file is created automatically when PyInstaller is executed, so it is recommended to modify the created one and use it.
If there are multiple files you want to add, the spec file is easier to use.
When building with a spec file:

pyinstaller main.spec

The above settings are fine for PyInstaller settings, but you may need to modify the source.
Described in the next section.

Specifying the path in the source

When using the --onefile option, the binary file specified with--add-binary is included in the exe. They are expanded to a temporary folder at runtime. Therefore, using relative paths in the Python source may not work.

For example, it is necessary to rewrite the part using the relative path as follows:

driver = webdriver.Chrome('./driver/chromedriver.exe')

Rewrite as follows (import the necessary modules):

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)

driver = webdriver.Chrome(resource_path('./driver/chromedriver.exe'))

Add the function resource_path to use it.
resource_path gets the path with the following logic:

  1. When executing from exe, get the relative path from sys._MEIPASS (when executing from exe, the temporary folder path is entered).
  2. When executing from Python, get the relative path from this file (__file__).

Now it works properly whether you run it from Python or an exe file.

At the end

This is the end of the explanation.
Although it was an example of Python & Selenium, I think that it is the same even if you want to include image files etc. in exe.



Related Posts