我使用Python,Pysimplegui和Praw创建一个Reddit机器人。它在我的空闲中运行,但在转换为可执行文件后因螺纹错误而失败

发布于 2025-01-28 21:13:15 字数 6103 浏览 5 评论 0原文

我正在研究一个机器人,该机器人使用Praw在用户定义的子reddit中扫描所有新评论,并搜索要回复的特定短语。我已经在这里看到了pysimplegui作为用户界面,您可以在此处看到:

gui的图像,带有reddit的文本输入的GUI图像API授权

由于在长时间操作中冻结的问题,我必须实现线程。我的代码只要我在闲置(pycharm)中运行它就可以运行良好:

ERROR  Unable to complete operation on element with key 0

File "PySimpleGUI\PySimpleGUI.py"   
line 20892
in_error_popup_with_traceback

You cannot perform operations (such as calling update) on an Element until:
window.read() is called or finalize=True when Window created.
Adding a "finalize=True" parameter to your Window creation will likely fix this.
The PySimpleGUI internal reporting function is _widget_was_created
The error originated from:
File "threading.py"
line 1319
in invoke_excepthook

此错误消息的屏幕截图。

我已经在此工作了两天,没有进一步的进步,尽管我对Python来说是全新的,所以我敢肯定我缺少一些东西。这是我的完整代码:

#importing the necessary libraries
from threading import Thread
import praw
import subprocess
import sys
import time
from datetime import datetime
import PySimpleGUI as psg

#worker function
def bot(id, secret, key, agent, user, sub, keywords, body):
    
    #initializes PRAW with user's credentials
    reddit = praw.Reddit(
        client_id=id,
        client_secret=secret,
        password=key,
        user_agent=agent,
        username=user)
    
    #specifies which subreddit to perform the operation on
    subreddit = reddit.subreddit(sub)
    
    #initiates a live feed of new comments and checks for the user defined search term using for loops
    for comment in subreddit.stream.comments():
        if comment:
            normalized_comment = comment.body.lower()
            for phrase in keywords:
                if phrase in normalized_comment:
                    
                    #if the phrase is found, prints a timestamp and the comment to the console
                    current_time = datetime.now()
                    print(str(current_time) + " - Replying to: " + '"' + comment.body + '"')
                    
                    #tries to reply to the comment found
                    try:                                                
                        comment.reply(body=body)
                        # A reply has been made so do not attempt to match other phrases.
                        break
                        
                    #if the bot is flagged for a cooldown, sleep for two minutes
                    except:
                        current_time = datetime.now()
                        print(str(current_time) + " - Rate limited, retrying in two minutes.")
                        time.sleep(120)

#this function creates the GUI
def gui():
    psg.theme("Dark")

    #layout for input window
    layout = [[psg.Text("Personal Use Script", size=(15, 1), font='Lucida', justification='right'), psg.Input()],
              [psg.Text("Secret", size=(15, 1), font='Lucida', justification='right'), psg.Input()],
              [psg.Text("Bot Password", size=(15, 1), font='Lucida', justification='right'), psg.Input()],
              [psg.Text("Bot Call Sign", size=(15, 1), font='Lucida', justification='right'), psg.Input()],
              [psg.Text("Bot Username", size=(15, 1), font='Lucida', justification='right'), psg.Input()],
              [psg.Text("Subreddit to Search", size=(15, 1), font='Lucida', justification='right'), psg.Input()],
              [psg.Text("Trigger Phrase", size=(15, 1), font='Lucida', justification='right'), psg.Input()],
              [psg.Text("Comment to Send", size=(15, 1), font='Lucida', justification='right'), psg.Input()],
              [psg.Button("RUN", font=("Times New Roman", 12))]]
    
    #this line initiates the GUI window
    win = psg.Window("Find & Reply v 0.1", layout, finalize=True, element_justification='c')
    
    #this line listens for any interactions with the elements on the window
    e, v = win.read()
    
    while True:
        
        #closes the program if the window is closed
        if e in (psg.WIN_CLOSED, 'Exit'):
            break
            
        #listens for the "RUN" button to be clicked and executes the bot function thread    
        if e == 'RUN':
            
            #this line closes the initial input window
            win.close()
            bot_thread = Thread(target=bot, args=(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]))
            bot_thread.start()

            # layout for a secondary output window so the user can read the console
            layout1 = [[psg.Output(size=(60, 15))]]
            
            #initiates the secondary window
            win1 = psg.Window("Scanning all new comments...", layout1, finalize=True, element_justification='c')
            
            #listens for any interactions with the elements on the window
            event, values = win1.Read()
            
            #closes the program in the event the window is close (doesn't work)
            if event in (psg.WIN_CLOSED, 'Exit'):
                break

            if event == 'Run':  # the two lines of code needed to get button and run command
                runCommand(cmd=values['_IN_'], window=win1)
            win1.close()

#this function sends the console text to the secondary output window for the user to read
def runCommand(cmd, timeout=None, window=None):
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    output = ''
    for line in p.stdout:
        line = line.decode(errors='replace' if (sys.version_info) < (3, 5) else 'backslashreplace').rstrip()
        output += line
        print(line)
        window.Refresh() if window else None        # yes, a 1-line if, so shoot me
    retval = p.wait(timeout)
    return (retval, output)                         # also return the output just for fun


if __name__ == '__main__':
    
    #this is where I initiate the GUI thread
    gui_thread = Thread(target=gui)
    gui_thread.start()

I'm working on a bot that uses PRAW to scan all new comments in a user defined subreddit and searches for specific phrases to reply to. I've used PySimpleGUI for the user interface, as you can see here:

Image of GUI with text inputs for Reddit API authorization

Because of an issue where it freezes during long operations, I've had to implement threading. My code runs well as long as I'm running it in my IDLE (PyCharm), but after converting it to an executable, running it, entering my credentials along with the relevant terms, and clicking "RUN", I get a threading error:

ERROR  Unable to complete operation on element with key 0

File "PySimpleGUI\PySimpleGUI.py"   
line 20892
in_error_popup_with_traceback

You cannot perform operations (such as calling update) on an Element until:
window.read() is called or finalize=True when Window created.
Adding a "finalize=True" parameter to your Window creation will likely fix this.
The PySimpleGUI internal reporting function is _widget_was_created
The error originated from:
File "threading.py"
line 1319
in invoke_excepthook

Screenshot of this error message.

I've been working on this for two days now with no further progress, although I am brand new to python so I'm sure I'm missing something. Here is my full code:

#importing the necessary libraries
from threading import Thread
import praw
import subprocess
import sys
import time
from datetime import datetime
import PySimpleGUI as psg

#worker function
def bot(id, secret, key, agent, user, sub, keywords, body):
    
    #initializes PRAW with user's credentials
    reddit = praw.Reddit(
        client_id=id,
        client_secret=secret,
        password=key,
        user_agent=agent,
        username=user)
    
    #specifies which subreddit to perform the operation on
    subreddit = reddit.subreddit(sub)
    
    #initiates a live feed of new comments and checks for the user defined search term using for loops
    for comment in subreddit.stream.comments():
        if comment:
            normalized_comment = comment.body.lower()
            for phrase in keywords:
                if phrase in normalized_comment:
                    
                    #if the phrase is found, prints a timestamp and the comment to the console
                    current_time = datetime.now()
                    print(str(current_time) + " - Replying to: " + '"' + comment.body + '"')
                    
                    #tries to reply to the comment found
                    try:                                                
                        comment.reply(body=body)
                        # A reply has been made so do not attempt to match other phrases.
                        break
                        
                    #if the bot is flagged for a cooldown, sleep for two minutes
                    except:
                        current_time = datetime.now()
                        print(str(current_time) + " - Rate limited, retrying in two minutes.")
                        time.sleep(120)

#this function creates the GUI
def gui():
    psg.theme("Dark")

    #layout for input window
    layout = [[psg.Text("Personal Use Script", size=(15, 1), font='Lucida', justification='right'), psg.Input()],
              [psg.Text("Secret", size=(15, 1), font='Lucida', justification='right'), psg.Input()],
              [psg.Text("Bot Password", size=(15, 1), font='Lucida', justification='right'), psg.Input()],
              [psg.Text("Bot Call Sign", size=(15, 1), font='Lucida', justification='right'), psg.Input()],
              [psg.Text("Bot Username", size=(15, 1), font='Lucida', justification='right'), psg.Input()],
              [psg.Text("Subreddit to Search", size=(15, 1), font='Lucida', justification='right'), psg.Input()],
              [psg.Text("Trigger Phrase", size=(15, 1), font='Lucida', justification='right'), psg.Input()],
              [psg.Text("Comment to Send", size=(15, 1), font='Lucida', justification='right'), psg.Input()],
              [psg.Button("RUN", font=("Times New Roman", 12))]]
    
    #this line initiates the GUI window
    win = psg.Window("Find & Reply v 0.1", layout, finalize=True, element_justification='c')
    
    #this line listens for any interactions with the elements on the window
    e, v = win.read()
    
    while True:
        
        #closes the program if the window is closed
        if e in (psg.WIN_CLOSED, 'Exit'):
            break
            
        #listens for the "RUN" button to be clicked and executes the bot function thread    
        if e == 'RUN':
            
            #this line closes the initial input window
            win.close()
            bot_thread = Thread(target=bot, args=(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]))
            bot_thread.start()

            # layout for a secondary output window so the user can read the console
            layout1 = [[psg.Output(size=(60, 15))]]
            
            #initiates the secondary window
            win1 = psg.Window("Scanning all new comments...", layout1, finalize=True, element_justification='c')
            
            #listens for any interactions with the elements on the window
            event, values = win1.Read()
            
            #closes the program in the event the window is close (doesn't work)
            if event in (psg.WIN_CLOSED, 'Exit'):
                break

            if event == 'Run':  # the two lines of code needed to get button and run command
                runCommand(cmd=values['_IN_'], window=win1)
            win1.close()

#this function sends the console text to the secondary output window for the user to read
def runCommand(cmd, timeout=None, window=None):
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    output = ''
    for line in p.stdout:
        line = line.decode(errors='replace' if (sys.version_info) < (3, 5) else 'backslashreplace').rstrip()
        output += line
        print(line)
        window.Refresh() if window else None        # yes, a 1-line if, so shoot me
    retval = p.wait(timeout)
    return (retval, output)                         # also return the output just for fun


if __name__ == '__main__':
    
    #this is where I initiate the GUI thread
    gui_thread = Thread(target=gui)
    gui_thread.start()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文