有一个名为
python-wd-parallel
的Python模块似乎具有某些功能用于此操作,但它来自2013年,现在是否仍然有用?我还发现了这个示例。还有
concurrent.futures
,这似乎更加新颖,但不太容易实现。 有没有人有使用Selenium的并行执行的工作示例?还可以使用线程和执行器来完成任务,但我觉得这样会更慢,因为它没有使用所有内核,仍然以序列形式运行。
使用Selenium进行并行执行的最新方式是什么?
有一个名为python-wd-parallel
的Python模块似乎具有某些功能用于此操作,但它来自2013年,现在是否仍然有用?我还发现了这个示例。
还有concurrent.futures
,这似乎更加新颖,但不太容易实现。 有没有人有使用Selenium的并行执行的工作示例?
还可以使用线程和执行器来完成任务,但我觉得这样会更慢,因为它没有使用所有内核,仍然以序列形式运行。
使用Selenium进行并行执行的最新方式是什么?
使用joblib的Parallel模块来实现,这是一个执行并行的绝佳库。
假设我们有一个名为urls
的URL列表,我们想要并行地对每个URL进行截图。
首先让我们导入必要的库。
from selenium import webdriver
from joblib import Parallel, delayed
现在让我们定义一个函数,它以base64格式获取屏幕截图
def take_screenshot(url):
phantom = webdriver.PhantomJS('/path/to/phantomjs')
phantom.get(url)
screenshot = phantom.get_screenshot_as_base64()
phantom.close()
return screenshot
现在要并行执行它,你需要做的是
screenshots = Parallel(n_jobs=-1)(delayed(take_screenshot)(url) for url in urls)
当这行代码执行完毕时,您将在screenshots
中拥有所有运行过程的数据。
关于并行计算的说明
Parallel(n_jobs=-1)
表示使用所有可用资源delayed(function)(input)
是joblib
创建要在并行上运行的函数输入的方式更多信息可以在joblib
文档中找到。
通常最好使用基于selenium和pytest的Python测试框架SeleniumBase。它非常完整,并支持所有性能提升、并行线程等功能。如果这不是你的情况,请继续阅读。
线程
和进程
都可以在selenium代码中大幅提高速度。下面给出了简短的示例。selenium工作由selenium_title
函数完成,该函数返回页面标题。这不涉及每个线程/进程执行期间发生的异常处理。有关此内容,请参见详细答案 - 处理异常。
concurrent.futures.ThreadPoolExecutor
}}。from selenium import webdriver
from concurrent import futures
def selenium_title(url):
wdriver = webdriver.Chrome() # chrome webdriver
wdriver.get(url)
title = wdriver.title
wdriver.quit()
return title
links = ["https://www.amazon.com", "https://www.google.com"]
with futures.ThreadPoolExecutor() as executor: # default/optimized number of threads
titles = list(executor.map(selenium_title, links))
concurrent.futures.ProcessPoolExecutor
。只需要在上面的代码中将 ThreadPoolExecuter
替换为 ProcessPoolExecutor
即可。它们都是从基类 Executor
派生而来。此外,你必须像下面这样保护主函数。if __name__ == '__main__':
with futures.ProcessPoolExecutor() as executor: # default/optimized number of processes
titles = list(executor.map(selenium_title, links))
尽管Python由于Python GIL对线程有限制,即使线程将被上下文切换。 由于Selenium的实现细节,性能提升将会出现。 Selenium通过发送命令(如POST
,GET
(HTTP请求
))来工作。 这些命令将被发送到浏览器驱动程序服务器。 因此,您可能已经知道I / O绑定任务(HTTP请求
)会释放GIL,从而提高性能。
我们可以对上面的示例进行小修改,以处理生成的线程中的Exceptions
。 我们使用executor.submit
而不是使用executor.map
。 那将返回包装在Future
实例中的标题。
要访问返回的标题,我们可以使用future_titles[index].result
,其中索引大小为len(links)
,或者简单地使用像下面这样的for
。
with futures.ThreadPoolExecutor() as executor:
future_titles = [ executor.submit(selenium_title, link) for link in links ]
for future_title, link in zip(future_titles, links):
try:
title = future_title.result() # can use `timeout` to wait max seconds for each thread
except Exception as exc: # this thread migh have had an exception
print('url {:0} generated an exception: {:1}'.format(link, exc))
future_titles
之外,我们还迭代links
,因此如果某个线程出现异常,我们就知道哪个url(link)
有问题。
futures.Future
类很酷,因为它们使您可以控制从每个线程接收到的结果。例如,它是否正确完成或是否出现异常等,更多信息请参见这里。futures.as_completed
更好,如果您不关心线程返回项的顺序。但是,由于使用该语法来控制异常有点丑陋,在此我省略了它。
Process
)或线程池(Threads
)之间几乎没有{{link1:区别}}。{{link2:这里}}也得出了类似的结论,即Python线程与进程在I/O绑定任务上的表现相似。