Как решить проблемы с urllib3.connectionpool, используемым в Selenium при распараллеливании автоматизации? - PullRequest
1 голос
/ 27 января 2020

Краткое описание

Я обрабатываю много страниц с селеном последовательно, но для повышения производительности я решил распараллелить обработку - разделить страницы на несколько потоков (Это можно сделать, поскольку страницы независимы друг от друга).

Вот упрощенный код:

def process_page(driver, page, lock):
    driver.get("page.url()")
    driver.find_element_by_css_selector("some selector")
    wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "some selector")))
    .
    .
    .
    with lock:
        for i in range(result_tuple.__len__()):
            logger.info(result_tuple[i])
    return result_tuple

def process_all_pages():
    def pages_processing(id, lock):
        result = []
        with MyWebDriver(webdriver_options) as driver:
            for i in range(50):
                result.append(process_page(driver, pages[id * 50 + i], lock))
        return result

    lock = threading.Lock()

    with ThreadPoolExecutor(4) as executor:
        futures = []
        for i in range(4):
            futures.append(executor.submit(pages_processing, i, lock))

        result = []
        for i in range(futures.__len__()):
            result.append(futures[i].result())

    return result

MyWebDriver - простой диспетчер контекста для драйвера Chrome, при входе в контекст он порождает новый экземпляр драйвера Chrome и когда он выходит из контекста, он закрывает данный экземпляр Chrome.

Этот код порождает 4 Chrome драйвера отдельно для каждого потока и заставляет работать селен в Chrome драйверы, а также каждый поток отдельно.

Проблема

Первые несколько секунд это работает как чудо, но через некоторое время в логгере и Selenium начинают появляться предупреждения похоже, перестает общаться с Chrome драйверами.

  • То же поведение наблюдается с любым количеством потоков, кроме случаев, когда он работает в одном потоке.
  • То же поведение, выполняемое либо на Windows, либо на Ubuntu

При необходимости я мог бы также предоставить журналы отладки, но не уверен, что что-то есть релевантно.

Предупреждения в логгере:

...
# With these first warnings selenium stops to communicate with some Chrome drivers - just nothing happens in some of them.
WARNING - urllib3.connectionpool - Connection pool is full, discarding connection: 127.0.0.1
WARNING - urllib3.connectionpool - Connection pool is full, discarding connection: 127.0.0.1
...
# These warnings come a bit later
WARNING - urllib3.connectionpool - Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.HTTPConnection object at 0x0000018343AB24A8>: Failed to establish a new connection: [WinError 10061] No connection could be made because the target machine actively refused it')': /session/9c9fc148f278aaa360a26d95eac0966e/url
WARNING - urllib3.connectionpool - Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.HTTPConnection object at 0x0000018348854E10>: Failed to establish a new connection: [WinError 10061] No connection could be made because the target machine actively refused it')': /session/9c9fc148f278aaa360a26d95eac0966e/url
WARNING - urllib3.connectionpool - Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.HTTPConnection object at 0x0000018348869710>: Failed to establish a new connection: [WinError 10061] No connection could be made because the target machine actively refused it')': /session/9c9fc148f278aaa360a26d95eac0966e/url
...

Протестированные обходные пути

Я пробовал эти патчи для установки более высокого максимального размера ( HTTPConnectionPool , HTTPSConnectionPool ) - { ссылка } - это не решило проблему, кстати. исправления были выполнены.

Далее я попытался установить более высокие значения num_pools в классе PoolManager - я изменил это только в исходных кодах, а также в maxsize в HTTPConnectionPool и HTTPSConnectionPool . Это фактически решило одну проблему - никаких предупреждений в журнале не было, НО связь селена с драйвером все еще зависла.

...