如何通过两个不同应用复用同一Firefox浏览器会话打开新标签?
关于复用Firefox会话打开多标签页的问题解答
我来给你捋捋这个问题哈,你的需求是可行的,但当前的实现方式不对,才会抛出"Session is already started"的异常,下面详细说清楚:
核心问题分析
你用应用1启动了Geckodriver服务(端口4444)并创建了一个浏览器会话,然后应用2直接通过RemoteWebDriver连接同一个端口尝试创建新会话——但Geckodriver默认一个服务实例只能绑定一个会话,所以当应用2发送创建新会话的请求时,服务会直接报错说会话已经启动了。
应用2确实需要连接localhost的4444端口,但不是用来创建新会话,而是要复用应用1已经创建好的那个会话。
正确的实现步骤
步骤1:应用1中获取会话ID并传递给应用2
在应用1创建完FirefoxDriver后,把当前会话的ID提取出来,通过进程间通信、文件存储或者其他你方便的方式传递给应用2:
// 应用1原有代码之后添加 FirefoxDriver driver = new FirefoxDriver(service, ffoptions, TimeSpan.FromSeconds(30)); driver.Navigate().GoToUrl("https://www.bing.com/"); // 获取会话ID和服务地址 string sessionId = driver.SessionId.ToString(); // 这里可以把sessionId传递给应用2,比如写入本地临时文件 System.IO.File.WriteAllText(@"C:\temp\session.txt", sessionId);
步骤2:应用2复用已有会话打开新标签页
应用2不要用DesiredCapabilities创建新会话,而是基于应用1传递过来的会话ID,绑定到已有的会话上。因为Selenium的RemoteWebDriver默认构造器是创建新会话,所以我们需要用反射来设置已有的会话ID:
// 应用2代码,先读取应用1传递的sessionId string sessionIdStr = System.IO.File.ReadAllText(@"C:\temp\session.txt"); SessionId sessionId = new SessionId(sessionIdStr); // 连接到Geckodriver服务 Uri serviceUri = new Uri("http://127.0.0.1:4444/"); RemoteWebDriver driverReUse = new RemoteWebDriver(serviceUri, new FirefoxOptions()); // 通过反射设置会话ID,绑定到已有会话 var sessionField = typeof(RemoteWebDriver).GetField("_sessionId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); sessionField.SetValue(driverReUse, sessionId); // 现在就可以复用会话打开新标签页了 // 方式1:执行JS打开新标签 driverReUse.ExecuteScript("window.open('https://www.google.com/');"); // 方式2:切换到新标签页(如果需要操作新页面) var allWindows = driverReUse.WindowHandles; driverReUse.SwitchTo().Window(allWindows[1]);
额外注意事项
- 确保应用1的
FirefoxDriver在应用2操作期间没有被关闭,否则会话会失效 - 如果两个应用是同一进程内的不同模块,其实可以直接在应用1中调用
driver.ExecuteScript("window.open(...)")打开新标签,不需要拆分到两个应用 - 如果你用的是较新版本的Selenium,也可以考虑使用
DriverService的会话复用相关配置,但对于你当前的版本(Selenium 3.8),反射绑定会话ID是最直接的方案
内容的提问来源于stack exchange,提问作者John Daves
相关产品推荐
相关产品推荐

