¿Cómo puedo volver a conectarme al navegador abierto por webdriver con selenium?

Resuelto imbaiye asked hace 6 años • 7 respuestas

Por razones desconocidas, mi navegador abre las páginas de prueba de mi servidor remoto muy lentamente. Entonces, estoy pensando que si puedo volver a conectarme al navegador después de salir del script pero no lo ejecuto, webdriver.quit()esto dejará el navegador abierto. Probablemente sea una especie de GANCHO o identificador de controlador web. Busqué el documento API de selenio pero no encontré ninguna función. Estoy usando Chrome 62,x64,windows 7,selenium 3.8.0. Apreciaré mucho si la pregunta se puede resolver o no.

imbaiye avatar Dec 18 '17 10:12 imbaiye
Aceptado

No , no puede volver a conectarse a la sesión de navegación web anterior después de salir del script. Incluso si puede extraer el Session IDy Cookiesotros atributos de sesión del contexto de navegación anterior , no podrá pasar esos atributos como HOOK al WebDriver .

Una forma más limpia sería llamar webdriver.quit()y luego abarcar un nuevo contexto de navegación .


Bucear profundo

Ha habido muchas discusiones e intentos de volver a conectar WebDriver a un contexto de navegación existente . En la discusión Permitir que el controlador web se adjunte a un navegador en ejecución, Simon Stewart [Creator WebDriver] mencionó claramente:

  • Volver a conectarse a un contexto de navegación existente es una característica específica del navegador y, por lo tanto, no se puede implementar de forma genérica.
  • Conexplorador de Internet, es posible iterar sobre las ventanas abiertas en el sistema operativo y encontrar el proceso de IE correcto al que adjuntar.
  • firefoxyGoogle Chromedebe iniciarse en un modo y configuración específicos, lo que efectivamente significa que simplemente conectarse a una instancia en ejecución no es técnicamente posible.

tl; dr.

webdriver.firefox.useExistente no implementado

undetected Selenium avatar Dec 18 '2017 06:12 undetected Selenium

, en realidad eso es bastante fácil de hacer.

Una sesión de Selenium <-> webdriver está representada por una URL de conexión y session_id, simplemente se vuelve a conectar a una existente.

Descargo de responsabilidad : el enfoque utiliza propiedades internas del selenio ("privadas", en cierto modo), que pueden cambiar en nuevas versiones; será mejor que no lo uses para código de producción; es mejor no usarlo contra SE remoto (su centro o proveedor como BrowserStack/Sauce Labs), debido a una advertencia/drenaje de recursos que se explica al final.

Cuando se inicia una instancia de webdriver, necesita obtener las propiedades mencionadas anteriormente; muestra:

from selenium import webdriver

driver = webdriver.Chrome()
driver.get('https://www.google.com/')

# now Google is opened, the browser is fully functional; print the two properties
# command_executor._url (it's "private", not for a direct usage), and session_id

print(f'driver.command_executor._url: {driver.command_executor._url}')
print(f'driver.session_id: {driver.session_id}')

Una vez conocidas esas dos propiedades, se puede conectar otra instancia; el "truco" consiste en iniciar un Remotecontrolador y proporcionar lo _urlanterior; así se conectará al proceso de selenio en ejecución:

driver2 = webdriver.Remote(command_executor=the_known_url)  
# when the started selenium is a local one, the url is in the form 'http://127.0.0.1:62526'

Cuando se ejecute, verá que se abre una nueva ventana del navegador.
Esto se debe a que al iniciar el controlador, la biblioteca de Selenium inicia automáticamente una nueva sesión y ahora tiene 1 proceso de controlador web con 2 sesiones (instancias de navegador).

Si navega a una URL, verá que se ejecuta en esa nueva instancia del navegador, no en la que quedó del inicio anterior, lo cual no es el comportamiento deseado.
En este punto, se deben hacer dos cosas: a) cerrar la sesión SE actual ("la nueva") y b) cambiar esta instancia a la sesión anterior:

if driver2.session_id != the_known_session_id:   # this is pretty much guaranteed to be the case
    driver2.close()   # this closes the session's window - it is currently the only one, thus the session itself will be auto-killed, yet:
    driver2.quit()    # for remote connections (like ours), this deletes the session, but does not stop the SE server

# take the session that's already running
driver2.session_id = the_known_session_id

# do something with the now hijacked session:
driver.get('https://www.bing.com/')

Y eso es todo: ahora está conectado a la sesión anterior/ya existente, con todas sus propiedades (cookies, LocalStorage, etc.).

Por cierto, no es necesario que los proporcione desired_capabilitiesal iniciar el nuevo controlador remoto; estos se almacenan y se heredan de la sesión existente que asumió.


Advertencia : tener un proceso SE en ejecución puede provocar una fuga de recursos en el sistema.

Siempre que uno se inicia y luego no se cierra, como en la primera parte del código, permanecerá allí hasta que lo elimine manualmente. Con esto quiero decir que, en Windows, por ejemplo, verás un proceso "chromedriver.exe", que tendrás que finalizar manualmente una vez que hayas terminado. No puede ser cerrado por un controlador que se haya conectado a él como a un proceso de selenio remoto.
La razón: cada vez que inicia una instancia de navegador local y luego llama a su quit()método, tiene 2 partes: la primera es eliminar la sesión de la instancia de Selenium (lo que se hace en el segundo fragmento de código), y la La otra es detener el servicio local (Chrome/geckodriver), que generalmente funciona bien.

La cuestión es que, para las sesiones remotas, falta la segunda pieza: su máquina local no puede controlar un proceso remoto, ese es el trabajo del concentrador de ese control remoto. Entonces esa segunda parte es literalmente una passdeclaración de Python: una operación no operativa.

Si inicia demasiados servicios de Selenium en un centro remoto y no tiene control sobre él, se producirá un drenaje de recursos de ese servidor. Los proveedores de la nube como BrowserStack toman medidas contra esto: están cerrando servicios sin actividad durante los últimos 60 años, etc., pero esto es algo que usted no desea hacer.

Y en cuanto a los servicios SE locales, no olvide limpiar ocasionalmente el sistema operativo de los controladores de Selenium huérfanos que olvidó :)

Todor Minakov avatar Aug 24 '2018 11:08 Todor Minakov

Bien, después de mezclar varias soluciones compartidas aquí y modificarlas, ahora tengo esto funcionando como se muestra a continuación. El script utilizará la ventana de Chrome abierta previamente, si está presente; la conexión remota es perfectamente capaz de cerrar el navegador si es necesario y el código funciona bien.

Me encantaría encontrar una forma de automatizar la obtención de session_id y la URL de la sesión activa anterior sin tener que escribirlos en un archivo durante la sesión anterior para recogerlos...

Esta es mi primera publicación aquí, así que me disculpo por romper las normas.

#Set manually - read/write from a file for automation
session_id =  "e0137cd71ab49b111f0151c756625d31"
executor_url = "http://localhost:50491"

def attach_to_session(executor_url, session_id):
    original_execute = WebDriver.execute
    def new_command_execute(self, command, params=None):
        if command == "newSession":
            # Mock the response
            return {'success': 0, 'value': None, 'sessionId': session_id}
        else:
            return original_execute(self, command, params)
    # Patch the function before creating the driver object
    WebDriver.execute = new_command_execute
    driver = webdriver.Remote(command_executor=executor_url, desired_capabilities={})
    driver.session_id = session_id
    # Replace the patched function with original function
    WebDriver.execute = original_execute
    return driver
 

remote_session = 0

#Try to connect to the last opened session - if failing open new window
try:
    driver = attach_to_session(executor_url,session_id)
    driver.current_url
    print(" Driver has an active window we have connected to it and running here now : ")
    print(" Chrome session ID ",session_id)
    print(" executor_url",executor_url)

except:
    print("No Driver window open - make a new one")
    driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()),options=myoptions)
    session_id = driver.session_id 
    executor_url = driver.command_executor._url
Rob Surf avatar Nov 17 '2022 14:11 Rob Surf

para Chromium puede obtener una lista de los procesos en ejecución del navegador, inspeccionar la línea de comandos de este proceso y buscar "--remote-debugging-port=", extraer ese número de puerto y usarlo en la inicialización del controlador web.

establezca las Opciones del controlador en

ChromiumOptions.DebuggerAddress = "127.0.0.1:" & remotePort

sin ninguna otra opción configurada iniciar

driver As IWebDriver = New EdgeDriver(driverService, ChromiumOptions, CommandTimeout)

Esa es la parte de VB.net que me funciona, pero creo que es posible traducirla y usarla en otros idiomas también.

y utilice el controlador como de costumbre. puede continuar en el punto donde la página se dejó abierta, o crear una ventana conocida y cerrar la anterior si desea comenzar de nuevo, pero con las cookies y el caché anteriores.

es posible que desee eliminar los procesos antiguos "webdriver.exe", porque en cada reconexión generará uno conocido.

de esta manera simulas el comportamiento real del usuario porque los usuarios normales no siempre navegan en privado. Regresaron a su sitio con cookies antiguas y datos en caché. para que pueda optimizar su sitio para manejar adecuadamente los activos almacenados en caché antiguos y encontrar formas en las que el usuario no necesite forzar la recarga del sitio o limpiar el caché cada vez que el sitio recibe una actualización.

Stefan D Schnurzegal avatar Jun 14 '2023 23:06 Stefan D Schnurzegal