使用 Tkinter 和 Selenium 进行多处理

Posted

技术标签:

【中文标题】使用 Tkinter 和 Selenium 进行多处理【英文标题】:Using Multiprocessing with Tkinter and Selenium 【发布时间】:2022-01-05 17:32:24 【问题描述】:

好的,所以我正在尝试创建一个用于控制 Selenium 进程的 Tkinter GUI。我想向 GUI 添加一个标签,从我按下开始按钮的那一刻起显示运行时。我想要的是运行时时钟在代码运行 Selenium 进程时自行更新。问题是当我按下“开始”按钮时,运行时时钟将更新第一秒,并且在 Selenium 进程完成之前不会再次更新。这是一个最小的可重现示例:

注意:如果您运行此代码,请注意 connect_driver() 函数安装 CHOMEDRIVER

import tkinter as tk
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager


class GUI():
    def __init__(self):
        self.root = tk.Tk()
        self.root.geometry("200x200")

        # run-time clock
        self.run_time_label = tk.Label(self.root, text="Run Time:")
        self.run_time_label.pack()
        self.run_time = tk.Label(self.root, text="00:00:00:00")
        self.run_time.pack()
        self.run_time_data = "days":0, "hours":0, "minutes":0, "seconds":0  

        # start button
        self.start_button = tk.Button(self.root, text="Start", bg="green", height=1, width=10, command=self.start)
        self.start_button.pack()

        self.root.mainloop()

    def start(self):
        self.update_runtime()
        self.change_state()
        self.connect_driver()
        self.work()

    def stop(self):
        driver.close()
        driver.quit()
        self.change_state()

    def update_runtime(self):
        if self.run_time_data["seconds"] < 59:
            self.run_time_data["seconds"] += 1
        elif self.run_time_data["seconds"] == 59:
            self.run_time_data["seconds"] = 0
            if self.run_time_data["minutes"] < 59:
                self.run_time_data["minutes"] += 1
            elif self.run_time_data["minutes"] == 59:
                self.run_time_data["minutes"] = 0
                if self.run_time_data["hours"] < 24:
                    self.run_time_data["hours"] += 1
                elif self.run_time_data["hours"] == 23:
                    self.run_time_data["hours"] = 0
                    self.run_time_data["days"] += 1
        
        time_string = ":02d::02d::02d::02d".format(self.run_time_data["days"],self.run_time_data["hours"],self.run_time_data["minutes"],self.run_time_data["seconds"])
        self.run_time.config(text=time_string)
        self.root.after(1000, self.update_runtime)

    def change_state(self):
        if self.start_button.cget("text") == "Start":
            self.start_button.configure(text="Stop", bg="red", command=self.stop)
        elif self.start_button.cget("text") == "Stop":
            self.start_button.configure(text="Start", bg="green", command=self.start)
        self.root.update_idletasks()

    def connect_driver(self):
        global driver
        driver = webdriver.Chrome(ChromeDriverManager().install())

    def work(self):
        for _ in range(3):
            driver.get("http://www.google.com")
            driver.get("https://***.com")
            driver.get("https://www.youtube.com")

if __name__ == "__main__":
    app = GUI()

运行此代码时,您可以看到运行时时钟将在按下“开始”后更新为 1 秒,然后继续执行 selenium 进程,但直到最后才会再次更新运行时时钟。所以我试图寻找解决方案,并认为我可能需要使用 Multiprocessing 来独立运行 update_runtime() 函数。问题是,我对 Multiprocessing 很陌生(显然),我应该如何在这里使用它并不是很明显。这是我尝试过的:

import tkinter as tk
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
import multiprocessing as mp


class GUI():
    def __init__(self):
        self.root = tk.Tk()
        self.root.geometry("200x200")

        # run-time clock
        self.run_time_label = tk.Label(self.root, text="Run Time:")
        self.run_time_label.pack()
        self.run_time = tk.Label(self.root, text="00:00:00:00")
        self.run_time.pack()
        self.run_time_data = "days":0, "hours":0, "minutes":0, "seconds":0  

        # start button
        self.start_button = tk.Button(self.root, text="Start", bg="green", height=1, width=10, command=self.start)
        self.start_button.pack()

        self.root.mainloop()

    def start(self):
        self.process = mp.Process(target=self.update_runtime)
        self.process.start()
        self.process.join()
        self.change_state()
        self.connect_driver()
        self.work()

    def stop(self):
        driver.close()
        driver.quit()
        self.change_state()

    def update_runtime(self):
        if self.run_time_data["seconds"] < 59:
            self.run_time_data["seconds"] += 1
        elif self.run_time_data["seconds"] == 59:
            self.run_time_data["seconds"] = 0
            if self.run_time_data["minutes"] < 59:
                self.run_time_data["minutes"] += 1
            elif self.run_time_data["minutes"] == 59:
                self.run_time_data["minutes"] = 0
                if self.run_time_data["hours"] < 24:
                    self.run_time_data["hours"] += 1
                elif self.run_time_data["hours"] == 23:
                    self.run_time_data["hours"] = 0
                    self.run_time_data["days"] += 1
        
        time_string = ":02d::02d::02d::02d".format(self.run_time_data["days"],self.run_time_data["hours"],self.run_time_data["minutes"],self.run_time_data["seconds"])
        self.run_time.config(text=time_string)
        self.root.after(1000, self.update_runtime)

    def change_state(self):
        if self.start_button.cget("text") == "Start":
            self.start_button.configure(text="Stop", bg="red", command=self.stop)
        elif self.start_button.cget("text") == "Stop":
            self.start_button.configure(text="Start", bg="green", command=self.start)
        self.root.update_idletasks()

    def connect_driver(self):
        global driver
        driver = webdriver.Chrome(ChromeDriverManager().install())

    def work(self):
        for _ in range(3):
            driver.get("http://www.google.com")
            driver.get("https://***.com")
            driver.get("https://www.youtube.com")

if __name__ == "__main__":
    app = GUI() 

但是当我运行它时,我得到一个错误:EOFError: Ran out of input

请帮忙! :)

【问题讨论】:

【参考方案1】:

不要使用多处理,而是尝试使用线程,就像更新一个标签这样简单的事情会更好。

https://realpython.com/intro-to-python-threading/

这样您就可以创建一个新函数,仅用于使用循环更新标签并在 start() 函数中调用它。

【讨论】:

当我要说使用线程。但是请提供一个示例,而不仅仅是一个链接? 该链接提供了示例并将实际解释如何使用它,而不是仅仅修复您的代码。 @M Z G 谢谢!我以前从未看过多线程,我一直认为它与多线程相同。刚刚实施,效果很好!另外,欢迎加入社区! 不建议使用外部链接作为答案,因为外部链接将来可能会失效。

以上是关于使用 Tkinter 和 Selenium 进行多处理的主要内容,如果未能解决你的问题,请参考以下文章

使用 tkinter 在 python 中进行多处理

使用 tkinter 进行多处理不会产生多个 GUI

Python多处理-TypeError:无法腌制'_tkinter.tkapp'对象

pyqt tkinter哪个好用

使用 tkinter 和多处理可执行创建多个窗口

Python:tkinter