pyinstaller and geckodriver generate issue after compile to exe

a 夏天 提交于 2021-02-19 06:24:05

问题


I hope i will get help here. I'm writing program who will read and export to txt 'devices live logging events' every two minutes. Everything works fine until i generate exe file. What is more interesting, program works on my enviroment(geckodriver and python libraries installed), but does not work on computers without python enviroment. Even if I generate exe with --onedir. Any ideas or tips? part of code is below(without tkinter):

browser = webdriver.Firefox()

def logs():
    global writing
    global browser
    logs_content = browser.find_element_by_css_selector(".content")
    if writing:
        curent_time = datetime.datetime.now()
        threading.Timer(120, logs).start()
        save_path = 'C:/Users/' + getpass.getuser() + '/Desktop/Logs ' + curent_time.strftime("%d-%B-%Y") + '.txt'
        with open(save_path, "w") as logs_txt:
            logs_txt.write(logs_content.text)

def enter_to_IDE():
    username = browser.find_element_by_id("username")
    username_input = login.get()
    username.send_keys(username_input)
    browser.find_element_by_id("next-step-btn").click()
    time.sleep(5)
    password_css = browser.find_element_by_id("password")
    password_input = password.get()
    password_css.send_keys(password_input)
    browser.find_element_by_id("login-user-btn").click()
    time.sleep(10)
    logs()

def US_shard():
    global browser
    browser.get('link')
    enter_to_IDE()


def EU_shard():
    global browser
    browser.get('link')
    enter_to_IDE()

回答1:


for future google users...

If you're having trouble tying to build a Selenium python script executable using pyinstaller

  1. Read the links and comments by furas above

  2. Add geckodriver to your build either by editing the .spec file or using --add-data ="<gecko location>;<build location>"

  3. the Default WebDriver constructor (used above) searches your PATH to find geckodriver, so you need to tell your code where to look for the driver if it's not in the system PATH

    • a user Andrew, had a good example here

The trouble with step 3 is getting a "location" that works in both your local interpreter, but also in your built executable. A hardcoded location on your PC will not work in the exe file. So pay attention to the source and destinations in --add-data, and maybe use relative paths.

Because I'm working with a repository with many users, I did not end up using the "all in one" option. Instead I wrote instructions to copy the geckodriver.exe along with my sample.exe file.

This 2 file solution does NOT need geckodriver in the exe file. Because Windows first checks the local folder you are in while searching PATH. source

Hope that is enough breadcrumbs to help future visitors. Also check this link for commands in pyinstaller

https://pyinstaller.readthedocs.io/en/stable/usage.html#options-group-what-to-bundle-where-to-search




回答2:


So i didn't want to blow away my old answer, I had issues getting this to work with Firefox/Geckodriver specifically. But I also just found out a solution to Chrome/Chromedriver a few seconds ago. Also I'm not working with Firefox anymore :-(

But this might work with recent versions of Selenium and Geckodriver.

Here is what I got. There are two halves to this problem.

  1. need to tell your python code where to look for your WebDriver when running as a .py and .exe
  2. need to run the PyInstaller app, with the proper directory specified.

The problem is, PyInstaller extracts everything to a TEMP directory. (for windows it's usually %TEMP%/_MEIxxxxx where XXXXX is a random number for each instance (allows for simultaneous running copies). This directory is deleted once your complied python .exe is finished running (or crashes because Selenium can't find the driver). Also this directory is most likely different from your Project Folder.

Section 1, the python code.

Project Structure Sources/chromedriver.exe main.py

import sys
import time
from selenium import webdriver

if hasattr(sys, "_MEIPASS"):
    print("TEMP PATH IS: %s " % sys._MEIPASS)
    work_dir = sys._MEIPASS
else:
    print("didn't have it")
    work_dir = os.getcwd()

time.sleep(20) # allows you to visually inspect the path above, shorten time at your discretion

chrome_driver_path = os.path.normpath(os.path.join(work_dir, "Sources/chromedriver.exe"))
driver = webdriver.Chrome(executable_path=chrome_driver_path )
driver.get("https://www.google.com")
time.sleep(10) # allows you to verify the page loaded

Section 2 - PyInstaller

enter this into a command prompt working out of your project folder, or put this into a batch file.

python -m PyInstaller ^
--onefile ^
--noconfirm ^
--name="main.exe" ^
--add-data="Sources\chromedriver.exe" ^
--clean ^
"main.py"

some of the flags like --noconfirm, and --clean are not quite needed for the batch, but it forces PyInstaller to overwrite the EXE when you compile again. Also if typing directly in a terminal/command prompt the carets ^ can be omitted as you will most likely not be using newlines (enter key)

Software Versions

Python 2.7.14 
selenium==3.14.1 
Chrome (64 bit) 85.0.4183.83
chromedriver --version ChromeDriver 85.0.4183.83 (win32.zip)

SAUCES :-)

  1. https://pyinstaller.readthedocs.io/en/stable/operating-mode.html#how-the-one-file-program-works
  2. https://chromedriver.chromium.org/downloads
  3. Packaging a script and data file using PyInstaller - how to use resource_path() (for _MEIxxxxx Temp folder)


来源:https://stackoverflow.com/questions/47747516/pyinstaller-and-geckodriver-generate-issue-after-compile-to-exe

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!