【问题标题】:How to reuse a selenium driver instance during parallel processing?如何在并行处理期间重用 selenium 驱动程序实例?
【发布时间】:2017-12-12 08:25:35
【问题描述】:

为了抓取 URL 池,我使用 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-line 需要放在scrape(URL) 之外。但是,scrape(URL) 之外的所有内容都无法找到 joblib 的Parallel(n_jobs = 40)。这意味着您不能在使用 joblib 进行抓取时重用驱动程序实例,这是不正确的。

Q1:上例并行处理时如何复用驱动实例?

Q2:如何在保持上述示例中的功能的同时摆脱while循环?

注意:firefox_profile 中禁用了 Flash 和图像加载(代码未显示)

【问题讨论】:

    标签: python selenium screen-scraping joblib


    【解决方案1】:

    1) 您应该首先创建一堆驱动程序:每个进程一个。并将实例传递给工作人员。我不知道如何将驱动程序传递给 Prallel 对象,但您可以使用 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是最好的(当然我可能错了,试试看)。

    【讨论】:

    • 看起来很有希望 - 我刚刚尝试过,但有些东西造成了内存泄漏 - 我一解决这个问题就会回复你
    • @sudonym,是什么造成了泄漏?
    • 泄漏是由于 phantomJS(我现在使用它而不是 Firefox) - 当 phantomJS 实例被重用时,已知“load_images = no argument”会导致这种情况
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-28
    • 1970-01-01
    • 2019-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多