Est-ce que quelqu'un sait si Selenium (WebDriver de préférence) est capable de communiquer avec et d'agir via un navigateur déjà en cours d'exécution avant de lancer un client Selenium?
Je veux dire si Selenium est capable de communiquer avec un navigateur sans utiliser le serveur Selenium (avec par exemple un Internet Explorer lancé manuellement).
Il s’agit d’une demande de fonctionnalité plutôt ancienne: Autoriser WebDriver à s’attacher à un navigateur en cours d’exécution . Donc, il n'est pas officiellement pris en charge.
Cependant, il existe un code fonctionnel qui prétend prendre en charge ceci: https://web.archive.org/web/20171214043703/http://tarunlalwani.com/post/reusing-existing-browser-session-Selenium -Java / .
Ceci est une réponse en double ** Reconnexion à un pilote dans python Selenium ** Ceci s’applique à tous les pilotes et pour Java api.
ouvrir un chauffeur
driver = webdriver.Firefox() #python
extraire dans session_id et _url à partir de l’objet driver.
url = driver.command_executor._url #"http://127.0.0.1:60622/hub"
session_id = driver.session_id #'4e167f26-dc1d-4f51-a207-f761eaf73c31'
Utilisez ces deux paramètres pour vous connecter à votre pilote.
driver = webdriver.Remote(command_executor=url,desired_capabilities={})
driver.session_id = session_id
Et vous êtes à nouveau connecté à votre pilote.
driver.get("http://www.mrsmart.in")
Cet extrait de code permet de réutiliser une instance de navigateur existante tout en évitant de créer un navigateur en double. Trouvé sur le blog de Tarun Lalwani .
from Selenium import webdriver
from Selenium.webdriver.remote.webdriver import WebDriver
# executor_url = driver.command_executor._url
# session_id = driver.session_id
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
bro = attach_to_session('http://127.0.0.1:64092', '8de24f3bfbec01ba0d82a7946df1d1c3')
bro.get('http://ya.ru/')
C'est possible. Mais vous devez le pirater un peu, il y a un code Ce que vous devez faire est de lancer un serveur autonome et de "patcher" RemoteWebDriver
public class CustomRemoteWebDriver : RemoteWebDriver
{
public static bool newSession;
public static string capPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestFiles", "tmp", "sessionCap");
public static string sessiodIdPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestFiles", "tmp", "sessionid");
public CustomRemoteWebDriver(Uri remoteAddress)
: base(remoteAddress, new DesiredCapabilities())
{
}
protected override Response Execute(DriverCommand driverCommandToExecute, Dictionary<string, object> parameters)
{
if (driverCommandToExecute == DriverCommand.NewSession)
{
if (!newSession)
{
var capText = File.ReadAllText(capPath);
var sidText = File.ReadAllText(sessiodIdPath);
var cap = JsonConvert.DeserializeObject<Dictionary<string, object>>(capText);
return new Response
{
SessionId = sidText,
Value = cap
};
}
else
{
var response = base.Execute(driverCommandToExecute, parameters);
var dictionary = (Dictionary<string, object>) response.Value;
File.WriteAllText(capPath, JsonConvert.SerializeObject(dictionary));
File.WriteAllText(sessiodIdPath, response.SessionId);
return response;
}
}
else
{
var response = base.Execute(driverCommandToExecute, parameters);
return response;
}
}
}
Jusqu'à présent, toutes les solutions manquaient de certaines fonctionnalités. Voici ma solution:
public class AttachedWebDriver extends RemoteWebDriver {
public AttachedWebDriver(URL url, String sessionId) {
super();
setSessionId(sessionId);
setCommandExecutor(new HttpCommandExecutor(url) {
@Override
public Response execute(Command command) throws IOException {
if (command.getName() != "newSession") {
return super.execute(command);
}
return super.execute(new Command(getSessionId(), "getCapabilities"));
}
});
startSession(new DesiredCapabilities());
}
}
Solution Javascript:
J'ai réussi à joindre une session de navigateur existante à l'aide de cette fonction
webdriver.WebDriver.attachToSession(executor, session_id);
La documentation peut être trouvée ici .
Inspiré par la réponse d’Eric, voici ma solution à ce problème pour Selenium 3.7.0. Par rapport à la solution de http://tarunlalwani.com/post/reusing-existing-browser-session-Selenium/ , l’avantage est qu’il n’y aura pas de fenêtre de navigateur vide à chaque connexion. à la session existante.
import warnings
from Selenium.common.exceptions import WebDriverException
from Selenium.webdriver.remote.errorhandler import ErrorHandler
from Selenium.webdriver.remote.file_detector import LocalFileDetector
from Selenium.webdriver.remote.mobile import Mobile
from Selenium.webdriver.remote.remote_connection import RemoteConnection
from Selenium.webdriver.remote.switch_to import SwitchTo
from Selenium.webdriver.remote.webdriver import WebDriver
# This webdriver can directly attach to an existing session.
class AttachableWebDriver(WebDriver):
def __init__(self, command_executor='http://127.0.0.1:4444/wd/hub',
desired_capabilities=None, browser_profile=None, proxy=None,
keep_alive=False, file_detector=None, session_id=None):
"""
Create a new driver that will issue commands using the wire protocol.
:Args:
- command_executor - Either a string representing URL of the remote server or a custom
remote_connection.RemoteConnection object. Defaults to 'http://127.0.0.1:4444/wd/hub'.
- desired_capabilities - A dictionary of capabilities to request when
starting the browser session. Required parameter.
- browser_profile - A Selenium.webdriver.firefox.firefox_profile.FirefoxProfile object.
Only used if Firefox is requested. Optional.
- proxy - A Selenium.webdriver.common.proxy.Proxy object. The browser session will
be started with given proxy settings, if possible. Optional.
- keep_alive - Whether to configure remote_connection.RemoteConnection to use
HTTP keep-alive. Defaults to False.
- file_detector - Pass custom file detector object during instantiation. If None,
then default LocalFileDetector() will be used.
"""
if desired_capabilities is None:
raise WebDriverException("Desired Capabilities can't be None")
if not isinstance(desired_capabilities, dict):
raise WebDriverException("Desired Capabilities must be a dictionary")
if proxy is not None:
warnings.warn("Please use FirefoxOptions to set proxy",
DeprecationWarning)
proxy.add_to_capabilities(desired_capabilities)
self.command_executor = command_executor
if type(self.command_executor) is bytes or isinstance(self.command_executor, str):
self.command_executor = RemoteConnection(command_executor, keep_alive=keep_alive)
self.command_executor._commands['GET_SESSION'] = ('GET', '/session/$sessionId') # added
self._is_remote = True
self.session_id = session_id # added
self.capabilities = {}
self.error_handler = ErrorHandler()
self.start_client()
if browser_profile is not None:
warnings.warn("Please use FirefoxOptions to set browser profile",
DeprecationWarning)
if session_id:
self.connect_to_session(desired_capabilities) # added
else:
self.start_session(desired_capabilities, browser_profile)
self._switch_to = SwitchTo(self)
self._mobile = Mobile(self)
self.file_detector = file_detector or LocalFileDetector()
self.w3c = True # added hardcoded
def connect_to_session(self, desired_capabilities):
response = self.execute('GET_SESSION', {
'desiredCapabilities': desired_capabilities,
'sessionId': self.session_id,
})
# self.session_id = response['sessionId']
self.capabilities = response['value']
Pour l'utiliser:
if use_existing_session:
browser = AttachableWebDriver(command_executor=('http://%s:4444/wd/hub' % ip),
desired_capabilities=(DesiredCapabilities.INTERNETEXPLORER),
session_id=session_id)
self.logger.info("Using existing browser with session id {}".format(session_id))
else:
browser = AttachableWebDriver(command_executor=('http://%s:4444/wd/hub' % ip),
desired_capabilities=(DesiredCapabilities.INTERNETEXPLORER))
self.logger.info('New session_id : {}'.format(browser.session_id))
J'ai eu une solution en python, j'ai modifié la classe webdriver bassed sur la classe PersistenBrowser que j'ai trouvée.
https://github.com/axelPalmerin/personal/commit/fabddb38a39f378aa113b0cb8d33391d5f91dca5
remplace le module Webdriver /usr/local/lib/python2.7/dist-packages/Selenium/webdriver/remote/webdriver.py
Ej. utiliser:
from Selenium.webdriver.common.desired_capabilities import DesiredCapabilities
runDriver = sys.argv[1]
sessionId = sys.argv[2]
def setBrowser():
if eval(runDriver):
webdriver = w.Remote(command_executor='http://localhost:4444/wd/hub',
desired_capabilities=DesiredCapabilities.CHROME,
)
else:
webdriver = w.Remote(command_executor='http://localhost:4444/wd/hub',
desired_capabilities=DesiredCapabilities.CHROME,
session_id=sessionId)
url = webdriver.command_executor._url
session_id = webdriver.session_id
print url
print session_id
return webdriver
Il semble que cette fonctionnalité ne soit pas officiellement prise en charge par Selenium. Cependant, Tarun Lalwani a créé un code de travail Java pour fournir la fonctionnalité. Voir - http://tarunlalwani.com/post/reusing-existing-browser-session-Selenium-Java) /
Voici l'exemple de code de travail, copié à partir du lien ci-dessus:
public static RemoteWebDriver createDriverFromSession(final SessionId sessionId, URL command_executor){
CommandExecutor executor = new HttpCommandExecutor(command_executor) {
@Override
public Response execute(Command command) throws IOException {
Response response = null;
if (command.getName() == "newSession") {
response = new Response();
response.setSessionId(sessionId.toString());
response.setStatus(0);
response.setValue(Collections.<String, String>emptyMap());
try {
Field commandCodec = null;
commandCodec = this.getClass().getSuperclass().getDeclaredField("commandCodec");
commandCodec.setAccessible(true);
commandCodec.set(this, new W3CHttpCommandCodec());
Field responseCodec = null;
responseCodec = this.getClass().getSuperclass().getDeclaredField("responseCodec");
responseCodec.setAccessible(true);
responseCodec.set(this, new W3CHttpResponseCodec());
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} else {
response = super.execute(command);
}
return response;
}
};
return new RemoteWebDriver(executor, new DesiredCapabilities());
}
public static void main(String [] args) {
ChromeDriver driver = new ChromeDriver();
HttpCommandExecutor executor = (HttpCommandExecutor) driver.getCommandExecutor();
URL url = executor.getAddressOfRemoteServer();
SessionId session_id = driver.getSessionId();
RemoteWebDriver driver2 = createDriverFromSession(session_id, url);
driver2.get("http://tarunlalwani.com");
}
Votre test doit avoir un RemoteWebDriver créé à partir d'une session de navigateur existante. Pour créer ce pilote, il vous suffit de connaître les "informations de session", c’est-à-dire l’adresse du serveur (local dans notre cas) où le navigateur est exécuté et l’identifiant de session du navigateur. Pour obtenir ces informations, nous pouvons créer une session de navigateur avec Selenium, ouvrir la page souhaitée, puis exécuter le script de test proprement dit.
Je ne sais pas s'il existe un moyen d'obtenir des informations de session pour une session qui n'a pas été créée par Selenium.
Voici un exemple d'informations sur la session:
Adresse du serveur distant: http: // localhost: 24266 . Le numéro de port est différent pour chaque session. ID de session: 534c7b561aacdd6dc319f60fed27d9d6.
J'utilise Rails + concombre + WebDriver Selenium + PhantomJS et j'utilise une version de Selenium Webdriver patché par un singe, ce qui permet de garder le navigateur PhantomJS ouvert entre les tests. Voir cet article de blog : http://blog.sharetribe.com/2014/04/07/faster-cucumber-startup-keep-phantomjs-browser-open-between-tests/
Voir aussi ma réponse à ce message: Comment puis-je exécuter une commande sur un navigateur déjà ouvert depuis un fichier Ruby
C'est assez facile avec JavaScript Selenium-webdriver
client:
Tout d'abord, assurez-vous qu'un serveur WebDriver est en cours d'exécution. Par exemple, téléchargez ChromeDriver , puis exécutez chromedriver --port=9515
.
Deuxièmement, créez le pilote comme ceci :
var driver = new webdriver.Builder()
.withCapabilities(webdriver.Capabilities.chrome())
.usingServer('http://localhost:9515') // <- this
.build();
Voici un exemple complet:
var webdriver = require ('Sélénium-webdriver');
var driver = new webdriver.Builder()
.withCapabilities(webdriver.Capabilities.chrome())
.usingServer('http://localhost:9515')
.build();
driver.get('http://www.google.com');
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver');
driver.findElement(webdriver.By.name('btnG')).click();
driver.getTitle().then(function(title) {
console.log(title);
});
driver.quit();