使用 C# Selenium Webdriver 正确附加到现有 chrome driver
Properly Attach to existing chrome driver with C# Selenium Webdriver
我使用了 Tarun Lalwani 设计的 method 通过重用 C# 中的 url 和 sessionID 来附加 Selenium Chrome driver。此附件部分有效,但某些 driver 方法(例如 FindElement(By.ID) 显示错误 "invalid argument: invalid locator (Session info: chrome= 91.0.4472.114)" 这一行:
var respBase = base.Execute(driverCommandToExecute, parameters);
我的猜测是,当 driver 为 attached.But 时,由于选项或所需功能为空,我还没有找到在 ReuseRemoteWebDriver 上正确设置它的方法。
附上外观的图片 driver
here。
我该如何解决这个问题,以便我可以附加之前的 chrome driver 并保留所有预期的 selenium 功能?
static void Main(string[] args)
{
InputSimulator teclado = new InputSimulator();
ChromeOptions options = new ChromeOptions();
options.UseSpecCompliantProtocol = true;
ChromeDriverService service = ChromeDriverService.CreateDefaultService(@"Thepathofchromedriver");
IWebDriver driver;
DesiredCapabilities capabilities = new DesiredCapabilities();
Uri myUri = new Uri("http://127.0.0.1:65431", UriKind.Absolute);
service.Port = 65431;
string ID = "1f42d5f0ad105910e8d2fc7be23480a9";
if (ID != "")
{
IWebDriver drivertest1 = new ChromeDriver(service, options);
IWebDriver drivertest = new ReuseRemoteWebDriver(myUri, ID,capabilities,options);
driver = drivertest;
}
else
{
IWebDriver drivertest = new ChromeDriver(service,options);
driver = drivertest;
}
IWebElement inputUser = driver.FindElement(By.Id("ID"));}
public class ReuseRemoteWebDriver : OpenQA.Selenium.Remote.RemoteWebDriver
{
private String _sessionId;
public ReuseRemoteWebDriver(Uri remoteAddress, String sessionId, OpenQA.Selenium.Remote.DesiredCapabilities capability, ChromeOptions options)
: base(remoteAddress,options)
{
this._sessionId = sessionId;
var sessionIdBase = this.GetType()
.BaseType
.GetField("sessionId",
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.NonPublic);
sessionIdBase.SetValue(this, new OpenQA.Selenium.Remote.SessionId(sessionId));
}
protected override OpenQA.Selenium.Remote.Response
Execute(string driverCommandToExecute, System.Collections.Generic.Dictionary<string, object> parameters)
{
if (driverCommandToExecute == OpenQA.Selenium.Remote.DriverCommand.NewSession)
{
var resp = new OpenQA.Selenium.Remote.Response();
resp.Status = OpenQA.Selenium.WebDriverResult.Success;
resp.SessionId = this._sessionId;
resp.Value = new System.Collections.Generic.Dictionary<String, Object>();
return resp;
}
var respBase = base.Execute(driverCommandToExecute, parameters);
return respBase;
}
}
更新:正如我在回复中指出的那样,我可以解决大多数问题。
我无法恢复的最重要的功能是使用
注入 js 脚本
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
var script = "your script";
js.ExecuteScript(script);
任何有关如何恢复注入脚本功能的想法都将不胜感激。
如果有人感兴趣,我将之前的 class 修改如下,这样我就可以使用 sendKeysToElement
public class ReuseRemoteWebDriver : OpenQA.Selenium.Remote.RemoteWebDriver
{
private String _sessionId;
public ReuseRemoteWebDriver(Uri remoteAddress, String sessionId, ChromeOptions options, ChromeDriverService service)
: base(remoteAddress, options)
{
//object x = driver;
this._sessionId = sessionId;
var sessionIdBase = this.GetType()
.BaseType
.GetField("sessionId",
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.NonPublic);
//System.Collections.Generic.Dictionary<string, object> x = this.GetCapabilitiesDictionary(capability);
sessionIdBase.SetValue(this, new OpenQA.Selenium.Remote.SessionId(sessionId));
}
protected override OpenQA.Selenium.Remote.Response
Execute(string driverCommandToExecute, System.Collections.Generic.Dictionary<string, object> parameters)
{
if (driverCommandToExecute == OpenQA.Selenium.Remote.DriverCommand.NewSession)
{
var resp = new OpenQA.Selenium.Remote.Response();
resp.Status = OpenQA.Selenium.WebDriverResult.Success;
resp.SessionId = this._sessionId;
resp.Value = new System.Collections.Generic.Dictionary<String, Object>();
return resp;
}
if (driverCommandToExecute == "sendKeysToElement")
{
object[] array = (object[])parameters["value"];
string stringfinal = (string)array[0].ToString();
parameters.Add("text", stringfinal);
}
if (driverCommandToExecute == "executeScript")
{
Console.WriteLine("");
}
var respBase = base.Execute(driverCommandToExecute, parameters);
return respBase;
}
}
}
在其他 class 中,我使用了以下方法来正确使用 Selenium 等待。
public Boolean WaitInteligente(WebDriverWait wait, string condition, By selector = null,
IWebElement optionalWebElement = null,string optionalstring = null,
bool optionalbool = false,bool devolverexcepcion=true )
{
TimeSpan Tiempo = wait.Timeout;
var globalclock = Stopwatch.StartNew();
Boolean stop = false;
double segundos = globalclock.Elapsed.TotalSeconds;
Exception exception = null;
//globalclock.Stop();
while (segundos <= Tiempo.TotalSeconds)
{
Thread.Sleep(500);
try
{
segundos = globalclock.Elapsed.TotalSeconds;
if (condition == "ElementExists")
wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementExists(selector));
if (condition == "ElementIsVisible")
wait.Until(ExpectedConditions.ElementIsVisible(selector));
if (condition == "ElementToBeClickable")
wait.Until(ExpectedConditions.ElementToBeClickable(selector));
if (condition == "ElementToBeSelected")
wait.Until(ExpectedConditions.ElementToBeSelected(selector));
if (condition == "FrameToBeAvailableAndSwitchToIt")
wait.Until(ExpectedConditions.FrameToBeAvailableAndSwitchToIt(selector));
if (condition == "InvisibilityOfElementLocated")
wait.Until(ExpectedConditions.InvisibilityOfElementLocated(selector));
if (condition == "PresenceOfAllElementsLocatedBy")
wait.Until(ExpectedConditions.PresenceOfAllElementsLocatedBy(selector));
if (condition == "VisibilityOfAllElementsLocatedBy")
wait.Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(selector));
if (condition == "AlertIsPresent")
wait.Until(ExpectedConditions.AlertIsPresent());
if (condition == "ElementToBeSelected")
wait.Until(ExpectedConditions.ElementToBeSelected(optionalWebElement));
if (condition == "InvisibilityOfElementWithText")
wait.Until(ExpectedConditions.InvisibilityOfElementWithText(selector,optionalstring));
if (condition == "StalenessOf")
wait.Until(ExpectedConditions.StalenessOf(optionalWebElement));
if (condition == "TextToBePresentInElement")
wait.Until(ExpectedConditions.TextToBePresentInElement(optionalWebElement,optionalstring));
if (condition == "TextToBePresentInElementLocated")
wait.Until(ExpectedConditions.TextToBePresentInElementLocated(selector, optionalstring));
if (condition == "TextToBePresentInElementValue")
wait.Until(ExpectedConditions.TextToBePresentInElementValue(selector, optionalstring));
if (condition == "TitleContains")
wait.Until(ExpectedConditions.TitleContains(optionalstring));
if (condition == "TitleIs")
wait.Until(ExpectedConditions.TitleIs(optionalstring));
if (condition == "UrlContains")
wait.Until(ExpectedConditions.UrlContains(optionalstring));
if (condition == "UrlMatches")
wait.Until(ExpectedConditions.UrlMatches(optionalstring));
if (condition == "UrlToBe")
wait.Until(ExpectedConditions.UrlToBe(optionalstring));
if (condition == "FrameToBeAvailableAndSwitchToIt")
wait.Until(ExpectedConditions.FrameToBeAvailableAndSwitchToIt(optionalstring));
if (condition == "AlertState")
wait.Until(ExpectedConditions.AlertState(optionalbool));
if (condition == "ElementSelectionStateToBe")
wait.Until(ExpectedConditions.ElementSelectionStateToBe(selector,optionalbool));
if (condition == "ElementSelectionStateToBe")
wait.Until(ExpectedConditions.ElementSelectionStateToBe(selector, optionalbool));
stop = true;
break;
}
catch (Exception e)
{
e = new Exception(selector.ToString() + condition + e.Message);
exception = e;
}
}
if (!stop && devolverexcepcion)
throw exception;
return stop;
}
附加后无法正常工作的方法是
driver.FindElement(By.Id) 和 driver.FindElement(By.ClassName) 可以通过分别对 ID 或类名调用 By.CssSelector 来轻松规避。
我无法恢复的最重要的功能是使用
注入 js 脚本
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
var script = "your script";
js.ExecuteScript(script);
任何关于如何恢复注入脚本功能的想法都将不胜感激。
我使用了 Tarun Lalwani 设计的 method 通过重用 C# 中的 url 和 sessionID 来附加 Selenium Chrome driver。此附件部分有效,但某些 driver 方法(例如 FindElement(By.ID) 显示错误 "invalid argument: invalid locator (Session info: chrome= 91.0.4472.114)" 这一行:
var respBase = base.Execute(driverCommandToExecute, parameters);
我的猜测是,当 driver 为 attached.But 时,由于选项或所需功能为空,我还没有找到在 ReuseRemoteWebDriver 上正确设置它的方法。 附上外观的图片 driver here。 我该如何解决这个问题,以便我可以附加之前的 chrome driver 并保留所有预期的 selenium 功能?
static void Main(string[] args)
{
InputSimulator teclado = new InputSimulator();
ChromeOptions options = new ChromeOptions();
options.UseSpecCompliantProtocol = true;
ChromeDriverService service = ChromeDriverService.CreateDefaultService(@"Thepathofchromedriver");
IWebDriver driver;
DesiredCapabilities capabilities = new DesiredCapabilities();
Uri myUri = new Uri("http://127.0.0.1:65431", UriKind.Absolute);
service.Port = 65431;
string ID = "1f42d5f0ad105910e8d2fc7be23480a9";
if (ID != "")
{
IWebDriver drivertest1 = new ChromeDriver(service, options);
IWebDriver drivertest = new ReuseRemoteWebDriver(myUri, ID,capabilities,options);
driver = drivertest;
}
else
{
IWebDriver drivertest = new ChromeDriver(service,options);
driver = drivertest;
}
IWebElement inputUser = driver.FindElement(By.Id("ID"));}
public class ReuseRemoteWebDriver : OpenQA.Selenium.Remote.RemoteWebDriver
{
private String _sessionId;
public ReuseRemoteWebDriver(Uri remoteAddress, String sessionId, OpenQA.Selenium.Remote.DesiredCapabilities capability, ChromeOptions options)
: base(remoteAddress,options)
{
this._sessionId = sessionId;
var sessionIdBase = this.GetType()
.BaseType
.GetField("sessionId",
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.NonPublic);
sessionIdBase.SetValue(this, new OpenQA.Selenium.Remote.SessionId(sessionId));
}
protected override OpenQA.Selenium.Remote.Response
Execute(string driverCommandToExecute, System.Collections.Generic.Dictionary<string, object> parameters)
{
if (driverCommandToExecute == OpenQA.Selenium.Remote.DriverCommand.NewSession)
{
var resp = new OpenQA.Selenium.Remote.Response();
resp.Status = OpenQA.Selenium.WebDriverResult.Success;
resp.SessionId = this._sessionId;
resp.Value = new System.Collections.Generic.Dictionary<String, Object>();
return resp;
}
var respBase = base.Execute(driverCommandToExecute, parameters);
return respBase;
}
}
更新:正如我在回复中指出的那样,我可以解决大多数问题。 我无法恢复的最重要的功能是使用
注入 js 脚本 IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
var script = "your script";
js.ExecuteScript(script);
任何有关如何恢复注入脚本功能的想法都将不胜感激。
如果有人感兴趣,我将之前的 class 修改如下,这样我就可以使用 sendKeysToElement
public class ReuseRemoteWebDriver : OpenQA.Selenium.Remote.RemoteWebDriver
{
private String _sessionId;
public ReuseRemoteWebDriver(Uri remoteAddress, String sessionId, ChromeOptions options, ChromeDriverService service)
: base(remoteAddress, options)
{
//object x = driver;
this._sessionId = sessionId;
var sessionIdBase = this.GetType()
.BaseType
.GetField("sessionId",
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.NonPublic);
//System.Collections.Generic.Dictionary<string, object> x = this.GetCapabilitiesDictionary(capability);
sessionIdBase.SetValue(this, new OpenQA.Selenium.Remote.SessionId(sessionId));
}
protected override OpenQA.Selenium.Remote.Response
Execute(string driverCommandToExecute, System.Collections.Generic.Dictionary<string, object> parameters)
{
if (driverCommandToExecute == OpenQA.Selenium.Remote.DriverCommand.NewSession)
{
var resp = new OpenQA.Selenium.Remote.Response();
resp.Status = OpenQA.Selenium.WebDriverResult.Success;
resp.SessionId = this._sessionId;
resp.Value = new System.Collections.Generic.Dictionary<String, Object>();
return resp;
}
if (driverCommandToExecute == "sendKeysToElement")
{
object[] array = (object[])parameters["value"];
string stringfinal = (string)array[0].ToString();
parameters.Add("text", stringfinal);
}
if (driverCommandToExecute == "executeScript")
{
Console.WriteLine("");
}
var respBase = base.Execute(driverCommandToExecute, parameters);
return respBase;
}
}
}
在其他 class 中,我使用了以下方法来正确使用 Selenium 等待。
public Boolean WaitInteligente(WebDriverWait wait, string condition, By selector = null,
IWebElement optionalWebElement = null,string optionalstring = null,
bool optionalbool = false,bool devolverexcepcion=true )
{
TimeSpan Tiempo = wait.Timeout;
var globalclock = Stopwatch.StartNew();
Boolean stop = false;
double segundos = globalclock.Elapsed.TotalSeconds;
Exception exception = null;
//globalclock.Stop();
while (segundos <= Tiempo.TotalSeconds)
{
Thread.Sleep(500);
try
{
segundos = globalclock.Elapsed.TotalSeconds;
if (condition == "ElementExists")
wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementExists(selector));
if (condition == "ElementIsVisible")
wait.Until(ExpectedConditions.ElementIsVisible(selector));
if (condition == "ElementToBeClickable")
wait.Until(ExpectedConditions.ElementToBeClickable(selector));
if (condition == "ElementToBeSelected")
wait.Until(ExpectedConditions.ElementToBeSelected(selector));
if (condition == "FrameToBeAvailableAndSwitchToIt")
wait.Until(ExpectedConditions.FrameToBeAvailableAndSwitchToIt(selector));
if (condition == "InvisibilityOfElementLocated")
wait.Until(ExpectedConditions.InvisibilityOfElementLocated(selector));
if (condition == "PresenceOfAllElementsLocatedBy")
wait.Until(ExpectedConditions.PresenceOfAllElementsLocatedBy(selector));
if (condition == "VisibilityOfAllElementsLocatedBy")
wait.Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(selector));
if (condition == "AlertIsPresent")
wait.Until(ExpectedConditions.AlertIsPresent());
if (condition == "ElementToBeSelected")
wait.Until(ExpectedConditions.ElementToBeSelected(optionalWebElement));
if (condition == "InvisibilityOfElementWithText")
wait.Until(ExpectedConditions.InvisibilityOfElementWithText(selector,optionalstring));
if (condition == "StalenessOf")
wait.Until(ExpectedConditions.StalenessOf(optionalWebElement));
if (condition == "TextToBePresentInElement")
wait.Until(ExpectedConditions.TextToBePresentInElement(optionalWebElement,optionalstring));
if (condition == "TextToBePresentInElementLocated")
wait.Until(ExpectedConditions.TextToBePresentInElementLocated(selector, optionalstring));
if (condition == "TextToBePresentInElementValue")
wait.Until(ExpectedConditions.TextToBePresentInElementValue(selector, optionalstring));
if (condition == "TitleContains")
wait.Until(ExpectedConditions.TitleContains(optionalstring));
if (condition == "TitleIs")
wait.Until(ExpectedConditions.TitleIs(optionalstring));
if (condition == "UrlContains")
wait.Until(ExpectedConditions.UrlContains(optionalstring));
if (condition == "UrlMatches")
wait.Until(ExpectedConditions.UrlMatches(optionalstring));
if (condition == "UrlToBe")
wait.Until(ExpectedConditions.UrlToBe(optionalstring));
if (condition == "FrameToBeAvailableAndSwitchToIt")
wait.Until(ExpectedConditions.FrameToBeAvailableAndSwitchToIt(optionalstring));
if (condition == "AlertState")
wait.Until(ExpectedConditions.AlertState(optionalbool));
if (condition == "ElementSelectionStateToBe")
wait.Until(ExpectedConditions.ElementSelectionStateToBe(selector,optionalbool));
if (condition == "ElementSelectionStateToBe")
wait.Until(ExpectedConditions.ElementSelectionStateToBe(selector, optionalbool));
stop = true;
break;
}
catch (Exception e)
{
e = new Exception(selector.ToString() + condition + e.Message);
exception = e;
}
}
if (!stop && devolverexcepcion)
throw exception;
return stop;
}
附加后无法正常工作的方法是 driver.FindElement(By.Id) 和 driver.FindElement(By.ClassName) 可以通过分别对 ID 或类名调用 By.CssSelector 来轻松规避。
我无法恢复的最重要的功能是使用
注入 js 脚本 IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
var script = "your script";
js.ExecuteScript(script);
任何关于如何恢复注入脚本功能的想法都将不胜感激。