Manter vivo o browser no Selenium

Manter vivo o browser no Selenium

Essa é uma dica bem simples e muitas vezes útil quando se está usando o Selenium. Nessa postagem usarei como exemplo o Chrome, porém, é possível fazer isso com qualquer outro browser.
Normalmente, nós fazemos algo como:

chrome = webdriver.Chrome()
...

Ou seja, sempre que formos executar essa linha, iniciamos um novo browser, ligamos a vida do processo dele ao nosso script e também ligamos a referência à variável determinada; como a vida do processo está ligada ao script, ao fim dele o browser é encerrado.
Em geral, esse é o comportamento desejado, porém há casos em estamos testando algo que precisa manter uma sessão que não possa ser destruída (como após preencher um formulário que não possa ser reenviado). Assim, o browser sempre ser encerrado complica nossos testes. Não podemos simplesmente matar o browser e iniciar um novo. Precisamos nos referenciar ao que já foi executado antes.

Como o tempo de vida do browser está ligado ao nosso script, uma forma de mantê-lo sempre vivo seria iniciar o browser fora dele. Uma forma bem prática é abrir o terminal, iniciar o REPL do Python3 e escrever

>>> from selenium import webdriver
>>> chrome = webdriver.Chrome()
>>> chrome.session_id
'462b8815d22f2612875eba9089329717'
>>> chrome.command_executor._url
'http://127.0.0.1:56714'

Desse modo, o REPL do Python está mantendo o processo do Chrome vivo, e facilmente conseguimos obter o ID da sessão dele. Além disso, também conseguimos a URL para acessa-lo, que será necessário logo abaixo.

Desse modo, no nosso script, ao invés de abrirmos um novo Chrome, podemos usar o Remote:

chrome = webdriver.Remote(command_executor='http://127.0.0.1:56714', desired_capabilities={})
chrome.session_id = '462b8815d22f2612875eba9089329717'

Agora, ele irá usar a mesma janela que já estava aberta previamente, mantendo todos os cookies e sessões já iniciadas.

Algo chato é que antes de trocar a sessão para o browser já aberto, ele abrirá uma nova janela que será inútil para nós. Para resolver isso, nós podemos reescrever o método start_session de Remote antes de criarmos o objeto:

def start_session(self, desired_capabilities, browser_profile=None):
    if browser_profile:
        desired_capabilities['firefox_profile'] = browser_profile.encoded

    #response = self.execute(Command.NEW_SESSION, {
    #    'desiredCapabilities': desired_capabilities,
    #})
    #self.session_id = response['sessionId']
    #self.capabilities = response['value']

    # Quick check to see if we have a W3C Compliant browser
    self.w3c = "specificationLevel" in self.capabilities

webdriver.Remote.start_session = start_session

A única diferença do start_session original são essas 5 linhas comentadas.
Como isso é um Monkey patch, tenha cuidado ao usar esse hack.

Agora, podemos manter um browser sempre vivo mesmo após o fim do script, muito útil para testes.