如何在多线程中 运行 `selenium-chromedriver`
How to run `selenium-chromedriver` in multiple threads
我正在使用 selenium
和 chrome-driver
从某些页面中 抓取 数据,然后 运行 使用该信息进行一些额外的任务(对于例如,在某些页面上输入一些评论)
我的程序有一个按钮。每次按下它都会调用 thread_(self)
(如下所示),启动一个新线程。目标函数 self.main
的代码 运行 所有 selenium 在 chrome-driver
.
上工作
def thread_(self):
th = threading.Thread(target=self.main)
th.start()
我的问题是在用户第一次按下之后。此 th
线程将打开浏览器 A 并执行一些操作。当浏览器 A 正在做一些事情时,用户将再次按下按钮并打开浏览器 B 与 运行 相同 self.main
。 我希望每个浏览器同时打开运行。我遇到的问题是,当我运行那个线程函数时,第一个浏览器停止,第二个浏览器打开.
我知道我的代码可以无限地创建线程。我知道这会影响个人电脑的性能,但我同意。 我想通过 self.main
!
加快完成的工作
试试这个:
def thread_(self):
th = threading.Thread(target=self.main)
self.jobs.append(th)
th.start()
Threading
selenium
加速
考虑以下函数来举例说明与单一 driver 方法相比,使用 selenium 的线程如何提供一些 speed-up。下面的代码 从使用 BeautifulSoup
的 selenium 打开的页面中删除 html 标题。页面列表为 links
.
import time
from bs4 import BeautifulSoup
from selenium import webdriver
import threading
def create_driver():
"""returns a new chrome webdriver"""
chromeOptions = webdriver.ChromeOptions()
chromeOptions.add_argument("--headless") # make it not visible, just comment if you like seeing opened browsers
return webdriver.Chrome(options=chromeOptions)
def get_title(url, webdriver=None):
"""get the url html title using BeautifulSoup
if driver is None uses a new chrome-driver and quit() after
otherwise uses the driver provided and don't quit() after"""
def print_title(driver):
driver.get(url)
soup = BeautifulSoup(driver.page_source,"lxml")
item = soup.find('title')
print(item.string.strip())
if webdriver:
print_title(webdriver)
else:
webdriver = create_driver()
print_title(webdriver)
webdriver.quit()
links = ["https://www.amazon.com", "https://www.google.com", "https://www.youtube.com/", "https://www.facebook.com/", "https://www.wikipedia.org/",
"https://us.yahoo.com/?p=us", "https://www.instagram.com/", "https://www.globo.com/", "https://outlook.live.com/owa/"]
现在 get_tile
在上面的 links
上打电话。
顺序方法
单个 chrome driver 并按顺序传递所有 link。我的机器耗时 22.3 秒(注:windows)。
start_time = time.time()
driver = create_driver()
for link in links: # could be 'like' clicks
get_title(link, driver)
driver.quit()
print("sequential took ", (time.time() - start_time), " seconds")
多线程方法
为每个 link 使用线程。结果在 10.5 秒内快了 2 倍。
start_time = time.time()
threads = []
for link in links: # each thread could be like a new 'click'
th = threading.Thread(target=get_title, args=(link,))
th.start() # could `time.sleep` between 'clicks' to see whats'up without headless option
threads.append(th)
for th in threads:
th.join() # Main thread wait for threads finish
print("multiple threads took ", (time.time() - start_time), " seconds")
This here and this better 是其他一些工作示例。第二个在 ThreadPool
上使用固定数量的线程。并建议存储在每个线程上初始化的 chrome-driver
实例比每次 creating-starting 更快。
我仍然不确定这是让 selenium 拥有可观的 speed-ups 的最佳方法。 因为 threading
on no IO bound code will end-up executed sequentially(一个线程接一个线程)。由于 Python GIL(全局解释器锁),Python 进程不能 运行 并行线程(利用多个 cpu-cores)。
Processes
selenium
加速
尝试使用包 multiprocessing
and Processes
class I wrote the following code and I ran multiple tests. I even added random page hyperlink clicks on the get_title
function above. Additional code is here.
克服 Python GIL 限制
start_time = time.time()
processes = []
for link in links: # each thread a new 'click'
ps = multiprocessing.Process(target=get_title, args=(link,))
ps.start() # could sleep 1 between 'clicks' with `time.sleep(1)``
processes.append(ps)
for ps in processes:
ps.join() # Main wait for processes finish
return (time.time() - start_time)
与我预期的相反 Python multiprocessing.Process
selenium
基于并行性平均 比 threading.Thread
. 慢大约 8%,但显然 booth 平均比顺序方法快两倍多。刚刚发现 selenium
chrome-driver 命令使用 HTTP-Requets
(如 POST
、GET
)所以它是 I/O 有界因此它释放 Python GIL 确实使其在线程中并行。
Threading
selenium
加速的良好开端 **
这不是确定的答案,因为我的测试只是一个很小的例子。此外,我使用的 Windows 和 multiprocessing
在这种情况下有很多限制。每个新的 Process
都不像 Linux 那样是一个分支,这意味着,除其他缺点外,还会浪费大量内存。
考虑到所有这些:根据用例,线程可能与尝试较重的进程方法一样好或更好(特别是 Windows用户)。
我正在使用 selenium
和 chrome-driver
从某些页面中 抓取 数据,然后 运行 使用该信息进行一些额外的任务(对于例如,在某些页面上输入一些评论)
我的程序有一个按钮。每次按下它都会调用 thread_(self)
(如下所示),启动一个新线程。目标函数 self.main
的代码 运行 所有 selenium 在 chrome-driver
.
def thread_(self):
th = threading.Thread(target=self.main)
th.start()
我的问题是在用户第一次按下之后。此 th
线程将打开浏览器 A 并执行一些操作。当浏览器 A 正在做一些事情时,用户将再次按下按钮并打开浏览器 B 与 运行 相同 self.main
。 我希望每个浏览器同时打开运行。我遇到的问题是,当我运行那个线程函数时,第一个浏览器停止,第二个浏览器打开.
我知道我的代码可以无限地创建线程。我知道这会影响个人电脑的性能,但我同意。 我想通过 self.main
!
试试这个:
def thread_(self):
th = threading.Thread(target=self.main)
self.jobs.append(th)
th.start()
Threading
selenium
加速
考虑以下函数来举例说明与单一 driver 方法相比,使用 selenium 的线程如何提供一些 speed-up。下面的代码 从使用 BeautifulSoup
的 selenium 打开的页面中删除 html 标题。页面列表为 links
.
import time
from bs4 import BeautifulSoup
from selenium import webdriver
import threading
def create_driver():
"""returns a new chrome webdriver"""
chromeOptions = webdriver.ChromeOptions()
chromeOptions.add_argument("--headless") # make it not visible, just comment if you like seeing opened browsers
return webdriver.Chrome(options=chromeOptions)
def get_title(url, webdriver=None):
"""get the url html title using BeautifulSoup
if driver is None uses a new chrome-driver and quit() after
otherwise uses the driver provided and don't quit() after"""
def print_title(driver):
driver.get(url)
soup = BeautifulSoup(driver.page_source,"lxml")
item = soup.find('title')
print(item.string.strip())
if webdriver:
print_title(webdriver)
else:
webdriver = create_driver()
print_title(webdriver)
webdriver.quit()
links = ["https://www.amazon.com", "https://www.google.com", "https://www.youtube.com/", "https://www.facebook.com/", "https://www.wikipedia.org/",
"https://us.yahoo.com/?p=us", "https://www.instagram.com/", "https://www.globo.com/", "https://outlook.live.com/owa/"]
现在 get_tile
在上面的 links
上打电话。
顺序方法
单个 chrome driver 并按顺序传递所有 link。我的机器耗时 22.3 秒(注:windows)。
start_time = time.time()
driver = create_driver()
for link in links: # could be 'like' clicks
get_title(link, driver)
driver.quit()
print("sequential took ", (time.time() - start_time), " seconds")
多线程方法
为每个 link 使用线程。结果在 10.5 秒内快了 2 倍。
start_time = time.time()
threads = []
for link in links: # each thread could be like a new 'click'
th = threading.Thread(target=get_title, args=(link,))
th.start() # could `time.sleep` between 'clicks' to see whats'up without headless option
threads.append(th)
for th in threads:
th.join() # Main thread wait for threads finish
print("multiple threads took ", (time.time() - start_time), " seconds")
This here and this better 是其他一些工作示例。第二个在 ThreadPool
上使用固定数量的线程。并建议存储在每个线程上初始化的 chrome-driver
实例比每次 creating-starting 更快。
我仍然不确定这是让 selenium 拥有可观的 speed-ups 的最佳方法。 因为 threading
on no IO bound code will end-up executed sequentially(一个线程接一个线程)。由于 Python GIL(全局解释器锁),Python 进程不能 运行 并行线程(利用多个 cpu-cores)。
Processes
selenium
加速
尝试使用包 multiprocessing
and Processes
class I wrote the following code and I ran multiple tests. I even added random page hyperlink clicks on the get_title
function above. Additional code is here.
start_time = time.time()
processes = []
for link in links: # each thread a new 'click'
ps = multiprocessing.Process(target=get_title, args=(link,))
ps.start() # could sleep 1 between 'clicks' with `time.sleep(1)``
processes.append(ps)
for ps in processes:
ps.join() # Main wait for processes finish
return (time.time() - start_time)
与我预期的相反 Python multiprocessing.Process
selenium
基于并行性平均 比 threading.Thread
. 慢大约 8%,但显然 booth 平均比顺序方法快两倍多。刚刚发现 selenium
chrome-driver 命令使用 HTTP-Requets
(如 POST
、GET
)所以它是 I/O 有界因此它释放 Python GIL 确实使其在线程中并行。
Threading
selenium
加速的良好开端 **
这不是确定的答案,因为我的测试只是一个很小的例子。此外,我使用的 Windows 和 multiprocessing
在这种情况下有很多限制。每个新的 Process
都不像 Linux 那样是一个分支,这意味着,除其他缺点外,还会浪费大量内存。
考虑到所有这些:根据用例,线程可能与尝试较重的进程方法一样好或更好(特别是 Windows用户)。