首页 > 解决方案 > Selenium / asyncio - 使用 Executor 而不重新生成 webdriver

问题描述

我有一个asyncio基于 -based 的爬虫,它偶尔会将需要浏览器的爬取卸载到 ThreadPoolExecutor,如下所示:

def browserfetch(url):
    browser = webdriver.Chrome()
    browser.get(url)
    # Some explicit wait stuff that can take up to 20 seconds.
    return browser.page_source

async def fetch(url, loop):
    with concurrent.futures.ThreadPoolExecutor() as pool:
        result = await loop.run_in_executor(pool, browserfetch, url)
    return result

我的问题是,我相信每次调用时都会重新生成无头浏览器fetch,这会导致每次调用时浏览器启动时间webdriver.Chrome。有没有办法让我重构browserfetch或者fetch可以在多个fetch调用中使用同一个无头驱动程序?

我尝试了什么?

我考虑过更明确地使用线程/池来Chrome在单独的线程/进程中启动实例,fetch通过队列、管道等在调用中进行通信(所有这些都运行Executors以防止调用阻塞)。不过,我不确定如何完成这项工作。

标签: pythonseleniumpython-asyncio

解决方案


我相信在单独的进程中启动浏览器并通过队列与他通信是一种很好的方法(并且更具可扩展性)。伪代码可能如下所示:

#  worker.py 
def entrypoint(in_queue, out_queue):  # run in process
    crawler = Crawler()
    browser = Browser()
    while not stop:
        command = in_queue.get()
        result = crawler.process(command, browser)
        out_queue.put(result)            

# main.py
import worker

in_queue, out_queue = Process(worker.entrypoint)
while not stop:
    in_queue.put(new_task)
    result = out_queue.get()

推荐阅读