如何在并行处理期间重用 selenium 驱动程序实例?
How to reuse a selenium driver instance during parallel processing?
为了收集 URLs 池,我正在使用 joblib 并行处理 selenium。在这种情况下,我面临两个挑战:
- 挑战1是加快这个过程。目前,我的代码为每个 URL 打开和关闭一个驱动程序实例(理想情况下每个进程都有一个)
- 挑战 2 是摆脱 CPU 密集的 while 循环,我认为我需要
continue
空结果(我知道这很可能是错误的)
伪代码:
URL_list = [URL1, URL2, URL3, ..., URL100000] # List of URLs to be scraped
def scrape(URL):
while True: # Loop needed to use continue
try: # Try scraping
driver = webdriver.Firefox(executable_path=path) # Set up driver
website = driver.get(URL) # Get URL
results = do_something(website) # Get results from URL content
driver.close() # Close worker
if len(results) == 0: # If do_something() failed:
continue # THEN Worker to skip URL
else: # If do_something() worked:
safe_results("results.csv") # THEN Save results
break # Go to next worker/URL
except Exception as e: # If something weird happens:
save_exception(URL, e) # THEN Save error message
break # Go to next worker/URL
Parallel(n_jobs = 40)(delayed(scrape)(URL) for URL in URL_list))) # Run in 40 processes
我的理解是,为了在迭代中重用驱动程序实例,# Set up driver
行需要放在 scrape(URL)
之外。但是,scrape(URL)
之外的所有内容都不会到达 joblib 的 Parallel(n_jobs = 40)
。这意味着您不能在使用 joblib 抓取时重用驱动程序实例,这是不正确的。
Q1:在上面的例子中并行处理时如何重用驱动实例?
问题 2:如何在保持上述示例功能的同时去掉 while 循环?
注意:Flash 和图像加载在 firefox_profile
中被禁用(代码未显示)
1) 您应该首先创建一组驱动程序:每个进程一个。并将实例传递给工作人员。我不知道如何将驱动程序传递给 Pralel 对象,但您可以使用 threading.current_thread().name
键来识别驱动程序。为此,请使用 backend="threading"
。所以现在每个线程都有自己的驱动程序。
2) 你根本不需要循环。并行对象本身会迭代你所有的 url(我希望我真的理解你使用循环的意图)
import threading
from joblib import Parallel, delayed
from selenium import webdriver
def scrape(URL):
try:
driver = drivers[threading.current_thread().name]
except KeyError:
drivers[threading.current_thread().name] = webdriver.Firefox()
driver = drivers[threading.current_thread().name]
driver.get(URL)
results = do_something(driver)
if results:
safe_results("results.csv")
drivers = {}
Parallel(n_jobs=-1, backend="threading")(delayed(scrape)(URL) for URL in URL_list)
for driver in drivers.values():
driver.quit()
但我真的不认为使用 n_job 比使用 CPU 更能获利。所以n_jobs=-1
是最好的(当然我可能错了,试试看)。
为了收集 URLs 池,我正在使用 joblib 并行处理 selenium。在这种情况下,我面临两个挑战:
- 挑战1是加快这个过程。目前,我的代码为每个 URL 打开和关闭一个驱动程序实例(理想情况下每个进程都有一个)
- 挑战 2 是摆脱 CPU 密集的 while 循环,我认为我需要
continue
空结果(我知道这很可能是错误的)
伪代码:
URL_list = [URL1, URL2, URL3, ..., URL100000] # List of URLs to be scraped
def scrape(URL):
while True: # Loop needed to use continue
try: # Try scraping
driver = webdriver.Firefox(executable_path=path) # Set up driver
website = driver.get(URL) # Get URL
results = do_something(website) # Get results from URL content
driver.close() # Close worker
if len(results) == 0: # If do_something() failed:
continue # THEN Worker to skip URL
else: # If do_something() worked:
safe_results("results.csv") # THEN Save results
break # Go to next worker/URL
except Exception as e: # If something weird happens:
save_exception(URL, e) # THEN Save error message
break # Go to next worker/URL
Parallel(n_jobs = 40)(delayed(scrape)(URL) for URL in URL_list))) # Run in 40 processes
我的理解是,为了在迭代中重用驱动程序实例,# Set up driver
行需要放在 scrape(URL)
之外。但是,scrape(URL)
之外的所有内容都不会到达 joblib 的 Parallel(n_jobs = 40)
。这意味着您不能在使用 joblib 抓取时重用驱动程序实例,这是不正确的。
Q1:在上面的例子中并行处理时如何重用驱动实例?
问题 2:如何在保持上述示例功能的同时去掉 while 循环?
注意:Flash 和图像加载在 firefox_profile
中被禁用(代码未显示)
1) 您应该首先创建一组驱动程序:每个进程一个。并将实例传递给工作人员。我不知道如何将驱动程序传递给 Pralel 对象,但您可以使用 threading.current_thread().name
键来识别驱动程序。为此,请使用 backend="threading"
。所以现在每个线程都有自己的驱动程序。
2) 你根本不需要循环。并行对象本身会迭代你所有的 url(我希望我真的理解你使用循环的意图)
import threading
from joblib import Parallel, delayed
from selenium import webdriver
def scrape(URL):
try:
driver = drivers[threading.current_thread().name]
except KeyError:
drivers[threading.current_thread().name] = webdriver.Firefox()
driver = drivers[threading.current_thread().name]
driver.get(URL)
results = do_something(driver)
if results:
safe_results("results.csv")
drivers = {}
Parallel(n_jobs=-1, backend="threading")(delayed(scrape)(URL) for URL in URL_list)
for driver in drivers.values():
driver.quit()
但我真的不认为使用 n_job 比使用 CPU 更能获利。所以n_jobs=-1
是最好的(当然我可能错了,试试看)。