Keep Selenium Webdriver across Celery Tasks

Viewed 411

I developed a Flask web app that uses Celery to handle tasks. One of these tasks consists of scraping a bunch of pages (around 200) using a custom Class derived from a selenium chrome driver.

@celery_app.task
def scrape_async():
   driver = MyDriver(exec_path=os.environ.get('CHROMEDRIVER_PATH'), options=some_chrome_options)
   
   # Update 'urls_to_scrape' attribute by finding the urls to scrape from a main url
   driver.find_urls_to_scrape_from_main_url()
   
   # Loop over each page and store the data in database
   for url in driver.urls_to_scrape:
      driver.scrape_page(url)

  # Exit driver
  driver.quit()

This worked well both in local and in production until the number of pages to scrape increased. I received a memory usage error on Heroku and realized how memory intensive the task was.

After some research, I found out that it would be easier to use a subtask in my loop (i.e. running this subtask for each page), as described below.

@celery_app.task
def subtask(url):
  driver.scrape_page(url)

@celery_app.task
def scrape_async():
   driver = MyDriver(exec_path=os.environ.get('CHROMEDRIVER_PATH'), options=some_chrome_options)
   
   # Update 'urls_to_scrape' attribute by finding the urls to scrape from a main url
   driver.find_urls_to_scrape_from_main_url()
   
   # Loop over each page and store the data in database
   for url in driver.urls_to_scrape:
      subtask.delay(url)

  # Exit driver
  driver.quit()

My concern is about how to keep the driver object between the main task and the subtask. I found this link, on how to instantiate Task but I couldn't manage to create one driver across multiple tasks.

Any idea on how to proceed to achieve my goal?

Thank you

0 Answers
Related