1

I am re-posting this question as it was closed.

However, How to add static(html, css, js) files in pyinstaller to create standalone exe file? is NOT a question identical to mine, as my GUI does not make use of any other types of files other then a .py file(code provided below). requests_html is just an imported module.


When I try to compile a simple GUI the compiled .exe file would open an empty command window for a few seconds and shuts down automatically.

I've tried using --hidden-import=sip and anything else I could find online but cannot get it working or figure out why it isn't working properly.

Since, I cannot get any error messages, I include the GUI code below.

Thanks in advance!

from PyQt5 import QtCore, QtWidgets
import sys
from PyQt5.QtWidgets import *
from PyQt5 import uic
from requests_html import HTMLSession
import os, os.path
import wget
import glob

from remove_empty import removeEmptyFolders

form_class = uic.loadUiType('light_gui.ui')[0]


class Ui_MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(Ui_MainWindow, self).__init__()
        self.setupUi(self)

        self.dir_open.clicked.connect(self.pick_dir)
        self.start_btn.clicked.connect(self.doong_light)



    def pick_dir(self):
        fname = QFileDialog.getExistingDirectory(self)
        self.down_path.setText('%s\\' % os.path.normpath(fname)) # os.path.normpath(path) --> Change "/" to "\" on Windows OS
        return(fname)



    def doong_light(self):
        def one_page_contents(target_page):
            contents = target_page.html.find('img')
            vid_contents = target_page.html.find('video')

            attached = []
            others = []

            for content in contents:
                if 'attach' in content.attrs['src']:
                    # print(content.attrs['src'][0])
                    # if content.attrs['src'][0] == '/files':
                    #     print('https://twicenest.com' + content.attrs['src'])
                    #     attached.append('https://twicenest.com' + content.attrs['src'])
                    # else:
                    #     attached.append(content.attrs['src'])
                    # attached.append(content.attrs['src'])
                    attached.append(str(content.attrs['src']))

                elif 'kakao' in content.attrs['src']:
                    others.append(content.attrs['src'])
                elif 'blogspot' in content.attrs['src']:
                    others.append(content.attrs['src'])
                try:
                    if '이미지' in content.attrs['alt']:
                        others.append(str(content.attrs['src']).split('?')[0] + '.jpg')
                except:
                    pass

            for content in vid_contents:
                if 'attach' in content.attrs['src']:
                    # if content.attrs['src'][0] == '/files':
                    #     attached.append('https://twicenest.com' + content.attrs['src'])
                    # else:
                    #     attached.append(content.attrs['src'])
                    # attached.append(content.attrs['src'])
                    attached.append(str(content.attrs['src']))

                elif 'kakao' in content.attrs['src']:
                    others.append(content.attrs['src'])
                elif 'blogspot' in content.attrs['src']:
                    others.append(content.attrs['src'])
                try:
                    if '비디오' in content.attrs['alt']:
                        others.append(str(content.attrs['src']).split('?')[0] + '.mp4')
                except:
                    pass

            return attached, others

        def alphanumeric(title):

            kill_list = '''!()-[]{};:'"\,<>./?@#$%^&*_~'''
            no_punct = ''

            for s in title:
                if s not in kill_list:
                    no_punct += s
            post_title = no_punct

            if len(post_title) >= 30:
                post_title = ('%.30s' % post_title)
                post_title = post_title.strip()

            return post_title

        def contents_download(attached, dst, post_title, error, title_num, choice):
            img_num = 1
            base_url = 'https://www.twicenest.com'
            base_url = str(base_url)

            for i in range(len(attached)):
                # print(content.attrs['src'][0])
                # if content.attrs['src'][0] == '/':
                #     print('https://twicenest.com' + content.attrs['src'])
                #     attached.append('https://twicenest.com' + content.attrs['src'])
                # else:
                #     attached.append(content.attrs['src'])
                # attached.append(content.attrs['src'])
                if attached[i][0] == '/':
                    img_url = base_url + attached[i]

                else:
                    img_url = attached[i]
                ### 글 하나에 있는 사진/영상 한폴더로 다운로드하기 위해 폴더 만들기###

                if choice == 2:

                    if not os.path.exists(dst + str(title_num) + '_' + str(post_title)):
                        print('폴더 만들기')
                        os.mkdir(dst + str(title_num) + '_' + str(post_title))

                    try:
                        wget.download(img_url, dst + str(title_num) + '_' + str(post_title) + '\\')

                    except:
                        error[post_title] = img_url
                        pass
                    file_list = glob.glob((dst + str(title_num) + '_' + str(post_title) + '\\*'))
                    if len(file_list) != 0:
                        latest_file = max(file_list, key=os.path.getctime)
                        if latest_file.split('.')[-1] == 'wget':
                            os.rename(latest_file,
                                      dst + str(title_num) + '_' + str(post_title) + '\\' + str(img_num) + str(
                                          post_title) + '.' + img_url.split('.')[-1])
                        else:
                            try:
                                os.rename(latest_file,
                                          dst + str(title_num) + '_' + str(post_title) + '\\' + str(img_num) + str(
                                              post_title) + '.' + img_url.split('.')[-1])
                            except:
                                pass

                        # file_name = latest_file.split('\\')[-1]

                        print(post_title + ' 다운 시작' + ' ' + str(img_num))
                        img_num += 1

                if choice == 1:
                    ### 다운 목표 페이지에 있는 모든 첨부 한폴더에 저장
                    try:
                        print(post_title + ' 다운 시작' + ' ' + str(img_num))
                        # print(img_url)
                        wget.download(img_url, dst)
                    except:
                        error[post_title] = img_url
                        pass
                    file_list = glob.glob((dst + '*'))
                    if len(file_list) >= 1:
                        latest_file = max(file_list, key=os.path.getctime)
                        # file_name = latest_file.split('\\')[-1]
                        if latest_file.split('.')[-1] == 'wget':
                            os.rename(latest_file, dst + str(img_num) + str(post_title) + '.' + img_url.split('.')[-1])
                        else:
                            try:
                                os.rename(latest_file,
                                          dst + str(post_title) + '_' +
                                          latest_file.split('.')[-2].split('\\')[-1] + str(img_num) + '.' +
                                          latest_file.split('.')[-1])
                            except:
                                pass

                    img_num += 1

            for key in error:
                error_path = key.strip()
                if not os.path.exists(dst + error_path):
                    os.mkdir(dst + error_path)
                try:
                    wget.download(error[key], dst + error_path)
                except:
                    # print(error[key])
                    pass

            title_num += 1

        # dst = input('다운 받을 경로 어디? : ')
        dst = str(self.down_path.text())

        print('')
        # url = input('다운 받을 페이지 url : ')
        url = str(self.target_url.text())
        session = HTMLSession()
        target_page = session.get(url)

        title = target_page.html.find('meta')[6].attrs['content']
        post_title = alphanumeric(title)

        error = dict()
        attached, others = one_page_contents(target_page)
        # print(attached, others)

        contents_download(attached, dst, post_title, error, 1, 1)
        contents_download(others, dst, post_title, error, 1, 1)
        removeEmptyFolders(dst)

        return attached, others

    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(389, 182)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.label_3 = QtWidgets.QLabel(self.centralwidget)
        self.label_3.setGeometry(QtCore.QRect(20, 10, 151, 16))
        self.label_3.setObjectName("label_3")
        self.widget = QtWidgets.QWidget(self.centralwidget)
        self.widget.setGeometry(QtCore.QRect(20, 40, 333, 82))
        self.widget.setObjectName("widget")
        self.gridLayout_2 = QtWidgets.QGridLayout(self.widget)
        self.gridLayout_2.setContentsMargins(0, 0, 0, 0)
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.gridLayout = QtWidgets.QGridLayout()
        self.gridLayout.setObjectName("gridLayout")
        self.label = QtWidgets.QLabel(self.widget)
        self.label.setObjectName("label")
        self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
        self.target_url = QtWidgets.QLineEdit(self.widget)
        self.target_url.setObjectName("target_url")
        self.gridLayout.addWidget(self.target_url, 0, 1, 1, 2)
        self.label_2 = QtWidgets.QLabel(self.widget)
        self.label_2.setObjectName("label_2")
        self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1)
        self.down_path = QtWidgets.QLineEdit(self.widget)
        self.down_path.setObjectName("down_path")
        self.gridLayout.addWidget(self.down_path, 1, 1, 1, 1)
        self.dir_open = QtWidgets.QPushButton(self.widget)
        self.dir_open.setObjectName("dir_open")
        self.gridLayout.addWidget(self.dir_open, 1, 2, 1, 1)
        self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)
        self.start_btn = QtWidgets.QPushButton(self.widget)
        self.start_btn.setObjectName("start_btn")
        self.gridLayout_2.addWidget(self.start_btn, 1, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 389, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.label_3.setText(_translate("MainWindow", "둥닷 다운로더 라이트 v1.0"))
        self.label.setText(_translate("MainWindow", "다운 받을 URL : "))
        self.label_2.setText(_translate("MainWindow", "다운 받을 폴더 : "))
        self.dir_open.setText(_translate("MainWindow", "..."))
        self.start_btn.setText(_translate("MainWindow", "GO!"))

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    light_gui = Ui_MainWindow()
    light_gui.show()
    sys.exit(app.exec_())

1 Answers1

0

I had a similar problem. I solved it with cx_Freeze instead of pyinstaller. First install cx_Freeze using pip as it is not an inbuilt python package.

Then make a directory with all the components, i.e. code and images(if any), of the GUI you are trying to make. Then create a new python file in the same directory named 'setup.py'. Then include the script that I am writing below into the setup.py file:

import cx_Freeze

executables = [cx_Freeze.Executable(<main python file that drives the GUI with .py extension>, base="Win32GUI")

cx_Freeze.setup(
    name=<name of the file in quotes>,
    options={"build_exe": {"packages": ["PyQt5", "sys", "requests_html", "os", "wget", "glob"], "include_files": [<list of all the external file names separated by , which is required by the main python script to run along with extensions, eg: images, sound or any other supporting python script>]}},
    executables = executables
)

Replace the text marked with <> with information as requested within quotes. Remember to use file extensions and give complete file path if the components are in some other directory.

Save the python file. Run cmd and navigate to the directory containg the setup.py and other components. From there type in the command python setup.py build

If everything is done correctly, then after completion of the cmd function successfully, you will have a new directory named 'build' inside of the directory you navigated to. Inside of that directory, you will find your .exe file with all the other components.

Edit: If you indeed have supporting files for your script, then don't separate the .exe from the other files, or else it won't work.

Sobhan Bose
  • 114
  • 9