简体   繁体   中英

Build a python selenium script into an exe using py2exe

I wrote a script in Python3.4 to navigate and login to a webpage using selenium. The script functions flawlessly. Selenium script:

from selenium import webdriver
from selenium.webdriver.common.keys import Keys

driver = webdriver.Firefox()
driver.get("http://128.114.70.78/periscope")
login = driver.find_element_by_id('keys')
login.send_keys("username")
login.send_keys(Keys.TAB)
login.send_keys("pass")
login.send_keys(Keys.RETURN)

I built it into an exe using py2exe, however the executable fails to import the selenium webdriver every time. I am getting an AttributeError: 'NoneType' object has no attribute 'startswith'. Here is the error in the log file:

Traceback (most recent call last):
File "periscopeLogin.py", line 1, in <module>
File "<frozen importlib._bootstrap>", line 2237, in _find_and_load
File "<frozen importlib._bootstrap>", line 2226, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 1191, in _load_unlocked
File "<frozen importlib._bootstrap>", line 1161, in 
_load_backward_compatible
File "C:\Python34\lib\site-packages\selenium\webdriver\__init__.py", line 
18, in <module>
 from .firefox.webdriver import WebDriver as Firefox  # noqa
File "<frozen importlib._bootstrap>", line 2237, in _find_and_load
File "<frozen importlib._bootstrap>", line 2226, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 1191, in _load_unlocked
File "<frozen importlib._bootstrap>", line 1161, in 
_load_backward_compatible
File "C:\Python34\lib\site-
packages\selenium\webdriver\firefox\webdriver.py", line 34, in <module>
 from selenium.webdriver.remote.webdriver import WebDriver as 
 RemoteWebDriver
File "<frozen importlib._bootstrap>", line 2237, in _find_and_load
File "<frozen importlib._bootstrap>", line 2226, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 1191, in _load_unlocked
File "<frozen importlib._bootstrap>", line 1161, in 
_load_backward_compatible
File "C:\Python34\lib\site-packages\selenium\webdriver\remote\webdriver.py", 
line 25, in <module>
 from .webelement import WebElement
File "<frozen importlib._bootstrap>", line 2237, in _find_and_load
File "<frozen importlib._bootstrap>", line 2226, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 1191, in _load_unlocked
File "<frozen importlib._bootstrap>", line 1161, in 
_load_backward_compatible
File "C:\Python34\lib\site-
packages\selenium\webdriver\remote\webelement.py", line 40, in <module>
 getAttribute_js = pkgutil.get_data(__package__, 
 'getAttribute.js').decode('utf8')
File "C:\Python34\lib\pkgutil.py", line 611, in get_data
 spec = importlib.util.find_spec(package)
File "C:\Python34\lib\importlib\util.py", line 81, in find_spec
 fullname = resolve_name(name, package) if name.startswith('.') else name
AttributeError: 'NoneType' object has no attribute 'startswith'

I found a thread from 2014 that says to specify the location of selenium webdriver in the setup.py file. Link: Make exe file from python selenium tests However, I still receive the same error when I try the thread's solution. Here is my setup.py:

from distutils.core import setup
import py2exe

data_files = [('selenium\webdriver\Firefox', ['C:\Python34\Lib\site-
packages\selenium\webdriver\Firefox\webdriver.xpi'])]
# from selenium import webdriver
# from selenium.webdriver.common.keys import Keys

setup(
    windows = [{'script': "periscopeLogin.py"}], # the main py file
    data_files = data_files,
    options = {
        'py2exe':
            {
                'skip_archive': True,
                'optimize': 2,
            }
    }
)

The only difference is that I'm using Python34, and the 3 year old thread uses Python27. I feel like things may have changed over that time span. Does anyone have any ideas or leads for me to follow? Should I just give it a shot with 27?

Thank you.

I ended up using python27 to get this to work, and solved my problem by putting together the answers from multiple threads with this issue. Here is a copy of the setup.py script I used:

from distutils.core import setup
import py2exe

setup(
    console=['periscopeLogin.py'],   # the main py file
    options={
            "py2exe":{
                    "packages": ["os", "linecache"],
                    "skip_archive": True, # tell script to not create a library folder
                    "unbuffered": True,
                    "optimize": 2
            }
    }
)

I think setting

"skip_archive" = True

is a personal preference, but a thread I followed said to do it.

The most significant problem is that py2exe does not copy over a few necessary files when creating the exe. You can fix this by finding the files in your python directory and manually copying them into your dist folder.

The first are " getAttribute " and " isDisplayed ". They can be located at

*pythonDirectory*\Lib\site-packages\selenium\webdriver\remote

My python directory is C:\\python27\\, so my files were found in

C:\Python27\Lib\site-packages\selenium\webdriver\remote.

Copy these two files, navigate to your dist folder, and paste them into

\dist\selenium\webdriver\remote

If you are using the Internet Explorer webdriver, this is all you need to do. I think the same for Chromedriver but I have not tested it.

If you're using Firefox, I know there are a couple more files you need to copy. They are " webdriver.xpi " and " webdriver_prefs.json ". You can locate them in:

*pythonDirectory*\Lib\site-packages\selenium\webdriver\firefox

Paste them into

\dist\selenium\webdriver\firefox

Now you should be good to go!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM