【问题标题】:Python How to run multiple functions every n seconds without interferencePython如何每n秒运行多个函数而不受干扰
【发布时间】:2020-10-18 22:46:28
【问题描述】:

所以假设我正在尝试使用 selenium 自动执行网页上的任务。

我必须单击多个按钮,这些按钮将我带到页面的不同部分,我必须在其中运行不同的功能来执行不同的任务。每次点击这些按钮,当相应的任务完成时,一个计时器就会出现在按钮的位置。当那个计时器用完时,我必须再次点击那个按钮并运行相应的任务功能,然后冲洗并重复。

这是我尝试过的代码:

import selenium
import threading

driver = webdriver.Chrome()
driver.get("https://example.com")

def foo1():
    button1 = driver.find_element_by_id("button1")
    button1.click()
    # do stuff
    timer = int(button1.text)
    threading.Timer(timer, foo1).start()

def foo2():
    button2 = driver.find_element_by_id("button2")
    button2.click()
    # do stuff
    timer = int(button2.text)
    threading.Timer(timer, foo2).start()

def foo3():
    button3 = driver.find_element_by_id("button3")
    button3.click()
    # do stuff
    timer = int(button3.text)
    threading.Timer(timer, foo3).start()

foo1()
foo2()
foo3()

现在,我的问题是,因为有多个这样的按钮,可能会出现一个计时器耗尽而另一个功能正在运行的情况。这会导致脚本在没有完成当前任务序列的情况下点击离开,从而终止其中一个线程。

我尝试过使用 threading.Lock() 对象,但它们没有解决问题。我有错误的方法还是我只是在这里遗漏了什么?

【问题讨论】:

  • 您应该在当前定义它们的函数之外创建和启动线程
  • 您在使用 Lock 对象时尝试了什么?您是在启动新计时器之前放置的吗?
  • @g2i 我在每个函数中定义了一个 Lock 对象,在开始时获取它,并在定义 Timer 对象之前释放它
  • @AbhinavMathur 你能详细说明一下吗?
  • @Emrys 为同样添加了答案

标签: python multithreading selenium


【解决方案1】:

您可以使用Lock 对象保持相同的代码结构。但是,您只需定义一个Lock 对象并在每个函数中获取/释放它,如下所示:

import selenium
import threading

driver = webdriver.Chrome()
driver.get("https://example.com")
lock = threading.Lock()

def foo1():
    lock.acquire()
    button1 = driver.find_element_by_id("button1")
    button1.click()
    # do stuff
    timer = int(button1.text)
    lock.release()
    threading.Timer(timer, foo1).start()

def foo2():
    lock.acquire()
    button2 = driver.find_element_by_id("button2")
    button2.click()
    # do stuff
    timer = int(button2.text)
    lock.release()
    threading.Timer(timer, foo2).start()

def foo3():
    lock.acquire()
    button3 = driver.find_element_by_id("button3")
    button3.click()
    # do stuff
    timer = int(button3.text)
    lock.release()
    threading.Timer(timer, foo3).start()

foo1()
foo2()
foo3()

通过这样做,您可以确保您的函数是原子的。例如,如果在执行foo1 时调用了foo2,那么foo2 将在foo1 调用lock.release() 时执行一次。

【讨论】:

  • 看起来像一个共同的Lock 对象主要是成功的。我在尝试使用它们时的错误是为每个单独的函数定义 Lock 对象。谢谢!
【解决方案2】:

对您的问题最不痛苦的解决方案是使用多个 webdriver 对象,每个对象位于不同的线程中,并使用您想要交流的变量的字典。

import time
def foo():
    driver = webdriver.Chrome()
    driver.get("https://example.com")
    button = driver.find_element_by_id("button")
    while True:
        button.click()
        # do stuff
        timer = int(button.text)
        time.sleep(timer)

据我所知,webdriver 对象不是线程安全的,因此最好跨多个线程复制它,而不是在不同线程中一遍又一遍地使用同一个对象。同样在您的解决方案中,您在每个不同的循环迭代中产生不同的线程,这可能会产生很多影响。 C++中类似情况的可以查看this的帖子

【讨论】:

  • 嗯,使用多个 webdriver 对象的问题是我正在使用的站点也有一个登录系统,如果我尝试从第二个实例登录,它会将我从第一个实例中注销一个
  • 抱歉回复晚了。您可以在实例之间共享 cookie。检查这个答案:stackoverflow.com/questions/32108933/… 因此,即使您使用多个实例,该站点就像只查看一个实例一样
【解决方案3】:

据我所知,可以改线程初始化来解决问题。

import selenium
import threading
import time 

driver = webdriver.Chrome()
driver.get("https://example.com")

def foo1():
    button1 = driver.find_element_by_id("button1")
    button1.click()
    # do stuff
    timer = int(button1.text)
    time.sleep(timer)
    foo1()
    
def foo2():
    button2 = driver.find_element_by_id("button2")
    button2.click()
    # do stuff
    timer = int(button2.text)
    time.sleep(timer)
    foo2()

t1 = threading.Thread(target=foo1)
t2 = threading.Thread(target=foo2)
t1.start()
t2.start()

【讨论】:

    猜你喜欢
    • 2012-06-04
    • 2020-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-23
    • 1970-01-01
    • 2017-08-13
    • 1970-01-01
    相关资源
    最近更新 更多